From dfaf556aeafcd25ef2374d835cd3925042107e95 Mon Sep 17 00:00:00 2001 From: Derrick Brashear Date: Wed, 30 Oct 2002 08:40:38 +0000 Subject: [PATCH] viced-cleanup-20021030 it all compiles nicely ==================== This delta was composed from multiple commits as part of the CVS->Git migration. The checkin message with each commit was inconsistent. The following are the additional commit messages. ==================== a little more cleanup ==================== a little more cleanup ==================== a little more cleanup ==================== a little more cleanup --- src/viced/afsfileprocs.c | 10575 ++++++++++++++++++------------------- src/viced/host.c | 89 +- src/viced/host.h | 48 +- src/viced/viced.c | 1407 +++-- 4 files changed, 6033 insertions(+), 6086 deletions(-) diff --git a/src/viced/afsfileprocs.c b/src/viced/afsfileprocs.c index 092e2c1f4..37fcde59e 100644 --- a/src/viced/afsfileprocs.c +++ b/src/viced/afsfileprocs.c @@ -357,2172 +357,1899 @@ static void CallPostamble(register struct rx_connection *aconn) } /*CallPostamble*/ +/* + * Returns the volume and vnode pointers associated with file Fid; the lock + * type on the vnode is set to lock. Note that both volume/vnode's ref counts + * are incremented and they must be eventualy released. + */ +static afs_int32 +CheckVnode(AFSFid *fid, Volume **volptr, Vnode **vptr, int lock) +{ + int fileCode = 0; + int errorCode = -1; + static struct timeval restartedat = {0,0}; -#define AFSV_BUFFERSIZE 16384 - -static struct afs_buffer { - struct afs_buffer *next; -} *freeBufferList = 0; -static int afs_buffersAlloced = 0; + if (fid->Volume == 0 || fid->Vnode == 0) /* not: || fid->Unique == 0) */ + return(EINVAL); + if ((*volptr) == 0) { + extern int VInit; -static FreeSendBuffer(register struct afs_buffer *adata) -{ - FS_LOCK - afs_buffersAlloced--; - adata->next = freeBufferList; - freeBufferList = adata; - FS_UNLOCK - return 0; + while(1) { + errorCode = 0; + *volptr = VGetVolume(&errorCode, (afs_int32)fid->Volume); + if (!errorCode) { + assert (*volptr); + break; + } + if ((errorCode == VOFFLINE) && (VInit < 2)) { + /* The volume we want may not be attached yet because + * the volume initialization is not yet complete. + * We can do several things: + * 1. return -1, which will cause users to see + * "connection timed out". This is more or + * less the same as always, except that the servers + * may appear to bounce up and down while they + * are actually restarting. + * 2. return VBUSY which will cause clients to + * sleep and retry for 6.5 - 15 minutes, depending + * on what version of the CM they are running. If + * the file server takes longer than that interval + * to attach the desired volume, then the application + * will see an ENODEV or EIO. This approach has + * the advantage that volumes which have been attached + * are immediately available, it keeps the server's + * immediate backlog low, and the call is interruptible + * by the user. Users see "waiting for busy volume." + * 3. sleep here and retry. Some people like this approach + * because there is no danger of seeing errors. However, + * this approach only works with a bounded number of + * clients, since the pending queues will grow without + * stopping. It might be better to find a way to take + * this call and stick it back on a queue in order to + * recycle this thread for a different request. + * 4. Return a new error code, which new cache managers will + * know enough to interpret as "sleep and retry", without + * the upper bound of 6-15 minutes that is imposed by the + * VBUSY handling. Users will see "waiting for + * busy volume," so they know that something is + * happening. Old cache managers must be able to do + * something reasonable with this, for instance, mark the + * server down. Fortunately, any error code < 0 + * will elicit that behavior. See #1. + * 5. Some combination of the above. I like doing #2 for 10 + * minutes, followed by #4. 3.1b and 3.2 cache managers + * will be fine as long as the restart period is + * not longer than 6.5 minutes, otherwise they may + * return ENODEV to users. 3.3 cache managers will be + * fine for 10 minutes, then will return + * ETIMEDOUT. 3.4 cache managers will just wait + * until the call works or fails definitively. + * NB. The problem with 2,3,4,5 is that old clients won't + * fail over to an alternate read-only replica while this + * server is restarting. 3.4 clients will fail over right away. + */ + if (restartedat.tv_sec == 0) { + /* I'm not really worried about when we restarted, I'm */ + /* just worried about when the first VBUSY was returned. */ + TM_GetTimeOfDay(&restartedat, 0); + return(VBUSY); + } + else { + struct timeval now; + TM_GetTimeOfDay(&now, 0); + if ((now.tv_sec - restartedat.tv_sec) < (11*60)) { + return(VBUSY); + } + else { + return (VRESTARTING); + } + } + } + /* allow read operations on busy volume */ + else if(errorCode==VBUSY && lock==READ_LOCK) { + errorCode=0; + break; + } + else if (errorCode) + return(errorCode); + } + } + assert (*volptr); -} /*FreeSendBuffer*/ + /* get the vnode */ + *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock); + if (errorCode) + return(errorCode); + if ((*vptr)->disk.uniquifier != fid->Unique) { + VPutVnode(&fileCode, *vptr); + assert(fileCode == 0); + *vptr = 0; + return(VNOVNODE); /* return the right error code, at least */ + } + return(0); +} /*CheckVnode*/ -/* allocate space for sender */ -static char *AllocSendBuffer() +/* + * This routine returns the ACL associated with the targetptr. If the + * targetptr isn't a directory, we access its parent dir and get the ACL + * thru the parent; in such case the parent's vnode is returned in + * READ_LOCK mode. + */ +static afs_int32 +SetAccessList(Vnode **targetptr, + Volume **volume, + struct acl_accessList **ACL, + int * ACLSize, + Vnode **parent, + AFSFid *Fid, + int Lock) { - register struct afs_buffer *tp; - - FS_LOCK - afs_buffersAlloced++; - if (!freeBufferList) { - FS_UNLOCK - return malloc(AFSV_BUFFERSIZE); + if ((*targetptr)->disk.type == vDirectory) { + *parent = 0; + *ACL = VVnodeACL(*targetptr); + *ACLSize = VAclSize(*targetptr); + return(0); + } + else { + assert(Fid != 0); + while(1) { + VnodeId parentvnode; + int errorCode = 0; + + parentvnode = (*targetptr)->disk.parent; + VPutVnode(&errorCode,*targetptr); + *targetptr = 0; + if (errorCode) return(errorCode); + *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK); + if (errorCode) return(errorCode); + *ACL = VVnodeACL(*parent); + *ACLSize = VAclSize(*parent); + if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0) + return(errorCode); + if ((*targetptr)->disk.parent != parentvnode) { + VPutVnode(&errorCode, *parent); + *parent = 0; + if (errorCode) return(errorCode); + } else + return(0); + } } - tp = freeBufferList; - freeBufferList = tp->next; - FS_UNLOCK - return (char *) tp; -} /*AllocSendBuffer*/ +} /*SetAccessList*/ -static int VolumeOwner (register struct client *client, - register Vnode *targetptr) +/* + * 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 + * in rights and anyrights, respectively + */ +static afs_int32 +GetRights (struct client *client, + struct acl_accessList *ACL, + afs_int32 *rights, + afs_int32 *anyrights) { - afs_int32 owner = V_owner(targetptr->volumePtr); /* get volume owner */ + extern prlist SystemAnyUserCPS; + afs_int32 hrights = 0; + int code; - if (owner >= 0) - return (client->ViceId == owner); - else { - /* - * We don't have to check for host's cps since only regular - * viceid are volume owners. - */ - return (acl_IsAMember(owner, &client->CPS)); + if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) { + + ViceLog(0,("CheckRights failed\n")); + *anyrights = 0; } + *rights = 0; + acl_CheckRights(ACL, &client->CPS, rights); -} /*VolumeOwner*/ + /* wait if somebody else is already doing the getCPS call */ + H_LOCK + while ( client->host->hostFlags & HCPS_INPROGRESS ) + { + client->host->hostFlags |= HCPS_WAITING; /* I am waiting */ +#ifdef AFS_PTHREAD_ENV + pthread_cond_wait(&client->host->cond, &host_glock_mutex); +#else /* AFS_PTHREAD_ENV */ + if ((code=LWP_WaitProcess( &(client->host->hostFlags))) !=LWP_SUCCESS) + ViceLog(0, ("LWP_WaitProcess returned %d\n", code)); +#endif /* AFS_PTHREAD_ENV */ + } -static int VolumeRootVnode (Vnode *targetptr) -{ - return ((targetptr->vnodeNumber == ROOTVNODE) && - (targetptr->disk.uniquifier == 1)); + if (client->host->hcps.prlist_len && !client->host->hcps.prlist_val) { + ViceLog(0,("CheckRights: len=%d, for host=0x%x\n", client->host->hcps.prlist_len, client->host->host)); + } else + 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)) + *rights |= implicitAdminRights; + *rights |= hrights; + *anyrights |= hrights; -} /*VolumeRootVnode*/ + return(0); + +} /*GetRights*/ /* - * This routine returns the status info associated with the targetptr vnode - * in the AFSFetchStatus structure. Some of the newer fields, such as - * SegSize and Group are not yet implemented + * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not + * a System:Administrator) */ -static -void GetStatus(Vnode *targetptr, - AFSFetchStatus *status, - afs_int32 rights, - afs_int32 anyrights, - Vnode *parentptr) +static afs_int32 +VanillaUser(struct client *client) { - /* initialize return status from a vnode */ - status->InterfaceVersion = 1; - status->SyncCounter = status->dataVersionHigh = status->lockCount = - status->errorCode = 0; - status->ResidencyMask = 1; /* means for MR-AFS: file in /vicepr-partition */ - if (targetptr->disk.type == vFile) - status->FileType = File; - else if (targetptr->disk.type == vDirectory) - status->FileType = Directory; - else if (targetptr->disk.type == vSymlink) - status->FileType = SymbolicLink; - else - status->FileType = Invalid; /*invalid type field */ - status->LinkCount = targetptr->disk.linkCount; - status->Length_hi = 0; - status->Length = targetptr->disk.length; - status->DataVersion = targetptr->disk.dataVersion; - status->Author = targetptr->disk.author; - status->Owner = targetptr->disk.owner; - status->CallerAccess = rights; - status->AnonymousAccess = anyrights; - status->UnixModeBits = targetptr->disk.modeBits; - status->ClientModTime = targetptr->disk.unixModifyTime; /* This might need rework */ - status->ParentVnode = (status->FileType == Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber); - status->ParentUnique = (status->FileType == Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier); - status->ServerModTime = targetptr->disk.serverModifyTime; - status->Group = targetptr->disk.group; - status->lockCount = targetptr->disk.lock.lockCount; - status->errorCode = 0; - -} /*GetStatus*/ - -afs_int32 SRXAFS_FetchData (struct rx_call *acall, - struct AFSFid *Fid, - afs_int32 Pos, - afs_int32 Len, - struct AFSFetchStatus *OutStatus, - struct AFSCallBack *CallBack, - struct AFSVolSync *Sync) + if (acl_IsAMember(SystemId, &client->CPS)) + return(0); /* not a system administrator, then you're "vanilla" */ + return(1); -{ - int code; +} /*VanillaUser*/ - code = common_FetchData (acall, Fid, Pos, Len, OutStatus, - CallBack, Sync, 0); - return code; -} -afs_int32 SRXAFS_FetchData64 (struct rx_call *acall, - struct AFSFid *Fid, - afs_int64 Pos, - afs_int64 Len, - struct AFSFetchStatus *OutStatus, - struct AFSCallBack *CallBack, - struct AFSVolSync *Sync) +/* + * This unusual afs_int32-parameter routine encapsulates all volume package related + * operations together in a single function; it's called by almost all AFS + * interface calls. + */ +static afs_int32 +GetVolumePackage(struct rx_connection *tcon, + AFSFid *Fid, + Volume **volptr, + Vnode **targetptr, + int chkforDir, + Vnode **parent, + struct client **client, + int locktype, + afs_int32 *rights, + afs_int32 *anyrights) { - int code; - afs_int32 tPos, tLen; + struct acl_accessList * aCL; /* Internal access List */ + int aCLSize; /* size of the access list */ + int errorCode = 0; /* return code to caller */ -#ifdef AFS_64BIT_ENV - if (Pos + Len > 0x7fffffff) - return E2BIG; - tPos = Pos; - tLen = Len; -#else /* AFS_64BIT_ENV */ - if (Pos.high || Len.high) - return E2BIG; - tPos = Pos.low; - tLen = Len.low; -#endif /* AFS_64BIT_ENV */ + if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype))) + return(errorCode); + if (chkforDir) { + if (chkforDir == MustNOTBeDIR && ((*targetptr)->disk.type == vDirectory)) + return(EISDIR); + else if (chkforDir == MustBeDIR && ((*targetptr)->disk.type != vDirectory)) + return(ENOTDIR); + } + if ((errorCode = SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent, (chkforDir == MustBeDIR ? (AFSFid *)0 : Fid), (chkforDir == MustBeDIR ? 0 : locktype))) != 0) + 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); + /* 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 */ + if ((*targetptr)->disk.owner == (*client)->ViceId) + (*rights) |= PRSFS_ADMINISTER; + else + (*rights) &= ~PRSFS_ADMINISTER; + } +#ifdef ADMIN_IMPLICIT_LOOKUP + /* admins get automatic lookup on everything */ + if (!VanillaUser(*client)) (*rights) |= PRSFS_LOOKUP; +#endif /* ADMIN_IMPLICIT_LOOKUP */ + return errorCode; - code = common_FetchData (acall, Fid, tPos, tLen, OutStatus, - CallBack, Sync, 1); - return code; -} +} /*GetVolumePackage*/ -static -afs_int32 common_FetchData64 (struct rx_call *acall, - struct AFSFid *Fid, - afs_int32 Pos, - afs_int32 Len, - struct AFSFetchStatus *OutStatus, - struct AFSCallBack *CallBack, - struct AFSVolSync *Sync, - int type) -{ - Vnode * targetptr = 0; /* pointer to vnode to fetch */ - Vnode * parentwhentargetnotdir = 0; /* parent vnode if vptr is a file */ - Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */ - 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 rx_connection *tcon; /* the connection we're part of */ - 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 */ -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval xferStartTime, - xferStopTime; /* Start/stop times for xfer portion*/ - struct timeval elapsedTime; /* Transfer time */ - afs_int32 bytesToXfer; /* # bytes to xfer*/ - afs_int32 bytesXferred; /* # bytes actually xferred*/ - int readIdx; /* Index of read stats array to bump*/ - static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */ - /* - * Set our stats pointers, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]); - xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ +/* + * This is the opposite of GetVolumePackage(), and is always used at the end of + * AFS calls to put back all used vnodes and the volume in the proper order! + */ +static afs_int32 +PutVolumePackage(Vnode *parentwhentargetnotdir, + Vnode *targetptr, + Vnode *parentptr, + Volume *volptr) +{ + int fileCode = 0; /* Error code returned by the volume package */ - ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n", - Fid->Volume, Fid->Vnode, Fid->Unique)); - FS_LOCK - AFSCallStats.FetchData++, AFSCallStats.TotalCalls++; - FS_UNLOCK + if (parentwhentargetnotdir) { + VPutVnode(&fileCode, parentwhentargetnotdir); + assert(!fileCode || (fileCode == VSALVAGE)); + } + if (targetptr) { + VPutVnode(&fileCode, targetptr); + assert(!fileCode || (fileCode == VSALVAGE)); + } + if (parentptr) { + VPutVnode(&fileCode, parentptr); + assert(!fileCode || (fileCode == VSALVAGE)); + } + if (volptr) { + VPutVolume(volptr); + } +} /*PutVolumePackage*/ - if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon)) - goto Bad_FetchData; +static int VolumeOwner (register struct client *client, + register Vnode *targetptr) +{ + afs_int32 owner = V_owner(targetptr->volumePtr); /* get volume owner */ - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n", - Fid->Volume, Fid->Vnode, Fid->Unique, - inet_ntoa(logHostAddr), t_client->ViceId)); - /* - * Get volume/vnode for the fetched file; caller's access rights to - * it are also returned - */ - if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, - DONTCHECK, &parentwhentargetnotdir, - &client, READ_LOCK, &rights, &anyrights))) - goto Bad_FetchData; + if (owner >= 0) + return (client->ViceId == owner); + else { + /* + * We don't have to check for host's cps since only regular + * viceid are volume owners. + */ + return (acl_IsAMember(owner, &client->CPS)); + } - SetVolumeSync(Sync, volptr); +} /*VolumeOwner*/ -#if FS_STATS_DETAILED - /* - * Remember that another read operation was performed. - */ - FS_LOCK - if (client->InSameNetwork) - readIdx = VOL_STATS_SAME_NET; - else - readIdx = VOL_STATS_DIFF_NET; - V_stat_reads(volptr, readIdx)++; - if (client->ViceId != AnonymousID) { - V_stat_reads(volptr, readIdx+1)++; - } - FS_UNLOCK -#endif /* FS_STATS_DETAILED */ - - /* Check whether the caller has permission access to fetch the data */ - if ((errorCode = Check_PermissionRights(targetptr, client, rights, - CHK_FETCHDATA, 0))) - goto Bad_FetchData; - - /* - * Drop the read lock on the parent directory after saving the parent - * vnode information we need to pass to GetStatus - */ - if (parentwhentargetnotdir != NULL) { - tparentwhentargetnotdir = *parentwhentargetnotdir; - VPutVnode(&fileCode, parentwhentargetnotdir); - assert(!fileCode || (fileCode == VSALVAGE)); - parentwhentargetnotdir = NULL; - } - -#if FS_STATS_DETAILED - /* - * Remember when the data transfer started. - */ - TM_GetTimeOfDay(&xferStartTime, 0); -#endif /* FS_STATS_DETAILED */ - - /* actually do the data transfer */ -#if FS_STATS_DETAILED - errorCode = FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type, - &bytesToXfer, &bytesXferred); -#else - if ((errorCode = FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type))) - goto Bad_FetchData; -#endif /* FS_STATS_DETAILED */ - -#if FS_STATS_DETAILED - /* - * At this point, the data transfer is done, for good or ill. Remember - * when the transfer ended, bump the number of successes/failures, and - * integrate the transfer size and elapsed time into the stats. If the - * operation failed, we jump to the appropriate point. - */ - TM_GetTimeOfDay(&xferStopTime, 0); - FS_LOCK - (xferP->numXfers)++; - if (!errorCode) { - (xferP->numSuccesses)++; - - /* - * Bump the xfer sum by the number of bytes actually sent, NOT the - * target number. - */ - tot_bytesXferred += bytesXferred; - (xferP->sumBytes) += (tot_bytesXferred >> 10); - tot_bytesXferred &= 0x3FF; - if (bytesXferred < xferP->minBytes) - xferP->minBytes = bytesXferred; - if (bytesXferred > xferP->maxBytes) - xferP->maxBytes = bytesXferred; - - /* - * Tally the size of the object. Note: we tally the actual size, - * NOT the number of bytes that made it out over the wire. - */ - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0) - (xferP->count[0])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1) - (xferP->count[1])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2) - (xferP->count[2])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3) - (xferP->count[3])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4) - (xferP->count[4])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5) - (xferP->count[5])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6) - (xferP->count[6])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7) - (xferP->count[7])++; - else - (xferP->count[8])++; - - fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime); - fs_stats_AddTo((xferP->sumTime), elapsedTime); - fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) { - fs_stats_TimeAssign((xferP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) { - fs_stats_TimeAssign((xferP->maxTime), elapsedTime); - } - } - FS_UNLOCK - /* - * Finally, go off to tell our caller the bad news in case the - * fetch failed. - */ - if (errorCode) - goto Bad_FetchData; -#endif /* FS_STATS_DETAILED */ - - /* write back the OutStatus from the target vnode */ - GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir); - - /* if a r/w volume, promise a callback to the caller */ - if (VolumeWriteable(volptr)) - SetCallBackStruct(AddCallBack(client->host, Fid), CallBack); - else { - struct AFSFid myFid; - memset(&myFid, 0, sizeof(struct AFSFid)); - myFid.Volume = Fid->Volume; - SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack); - } - -Bad_FetchData: - /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode)); - CallPostamble(tcon); - -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (errorCode == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } - -#endif /* FS_STATS_DETAILED */ - - osi_auditU (acall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END); - return(errorCode); - -} /*SRXAFS_FetchData*/ - - -afs_int32 SRXAFS_FetchACL (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSOpaque *AccessList, - struct AFSFetchStatus *OutStatus, - struct AFSVolSync *Sync) -{ - Vnode * targetptr = 0; /* pointer to vnode to fetch */ - 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 */ - afs_int32 rights, anyrights; /* rights for this and any user */ - struct rx_connection *tcon = rx_ConnectionOf(acall); - struct client *t_client; /* tmp ptr to client data */ - struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ - - /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ - - ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n", - Fid->Volume, Fid->Vnode, Fid->Unique)); - FS_LOCK - AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++; - FS_UNLOCK - if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_FetchACL; - - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n", - Fid->Volume, Fid->Vnode, Fid->Unique, - inet_ntoa(logHostAddr), t_client->ViceId)); - - AccessList->AFSOpaque_len = 0; - AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX); - - /* - * Get volume/vnode for the fetched file; caller's access rights to it - * are also returned - */ - if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, - DONTCHECK, &parentwhentargetnotdir, - &client, READ_LOCK, &rights, &anyrights))) - goto Bad_FetchACL; - - SetVolumeSync(Sync, volptr); - - /* Check whether we have permission to fetch the ACL */ - if ((errorCode = Check_PermissionRights(targetptr, client, rights, - CHK_FETCHACL, 0))) - goto Bad_FetchACL; - - /* Get the Access List from the dir's vnode */ - if ((errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir, - AccessList))) - goto Bad_FetchACL; - - /* Get OutStatus back From the target Vnode */ - GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir); - -Bad_FetchACL: - /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n", - errorCode, AccessList->AFSOpaque_val)); - CallPostamble(tcon); - -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (errorCode == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } - -#endif /* FS_STATS_DETAILED */ - - osi_auditU (acall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END); - return errorCode; -} /*SRXAFS_FetchACL*/ +static int VolumeRootVnode (Vnode *targetptr) +{ + return ((targetptr->vnodeNumber == ROOTVNODE) && + (targetptr->disk.uniquifier == 1)); +} /*VolumeRootVnode*/ /* - * This routine is called exclusively by SRXAFS_FetchStatus(), and should be - * merged into it when possible. + * Check if target file has the proper access permissions for the Fetch + * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL, + * StoreStatus) related calls */ -static -afs_int32 SAFSS_FetchStatus (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSFetchStatus *OutStatus, - struct AFSCallBack *CallBack, - struct AFSVolSync *Sync) -{ - Vnode * targetptr = 0; /* pointer to vnode to fetch */ - 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 */ - 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 */ - struct rx_connection *tcon = rx_ConnectionOf(acall); - - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1, ("SAFS_FetchStatus, Fid = %u.%d.%d, Host %s, Id %d\n", - Fid->Volume, Fid->Vnode, Fid->Unique, - inet_ntoa(logHostAddr), t_client->ViceId)); - FS_LOCK - AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++; - FS_UNLOCK - /* - * Get volume/vnode for the fetched file; caller's rights to it are - * also returned - */ - if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, - DONTCHECK, &parentwhentargetnotdir, - &client, READ_LOCK, &rights, &anyrights))) - goto Bad_FetchStatus; - - /* set volume synchronization information */ - SetVolumeSync(Sync, volptr); - - /* Are we allowed to fetch Fid's status? */ - if (targetptr->disk.type != vDirectory) { - if ((errorCode = Check_PermissionRights(targetptr, client, rights, - CHK_FETCHSTATUS, 0))) { - if (rx_GetCallAbortCode(acall) == errorCode) - rx_SetCallAbortCode(acall, 0); - goto Bad_FetchStatus; - } - } - - /* set OutStatus From the Fid */ - GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir); - - /* If a r/w volume, also set the CallBack state */ - if (VolumeWriteable(volptr)) - SetCallBackStruct(AddCallBack(client->host, Fid), CallBack); - else { - struct AFSFid myFid; - memset(&myFid, 0, sizeof(struct AFSFid)); - myFid.Volume = Fid->Volume; - SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack); - } - -Bad_FetchStatus: - /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode)); - return errorCode; - -} /*SAFSS_FetchStatus*/ - - -afs_int32 SRXAFS_BulkStatus(struct rx_call *acall, - struct AFSCBFids *Fids, - struct AFSBulkStats *OutStats, - struct AFSCBs *CallBacks, - struct AFSVolSync *Sync) -{ - register int i; - afs_int32 nfiles; - Vnode * targetptr = 0; /* pointer to vnode to fetch */ - 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 */ - 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); -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ - - /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ - - ViceLog(1, ("SAFS_BulkStatus\n")); - FS_LOCK - AFSCallStats.TotalCalls++; - FS_UNLOCK - - nfiles = Fids->AFSCBFids_len; /* # of files in here */ - if (nfiles <= 0) { /* Sanity check */ - errorCode = EINVAL; - goto Audit_and_Return; - } - - /* allocate space for return output parameters */ - OutStats->AFSBulkStats_val = (struct AFSFetchStatus *) - malloc(nfiles * sizeof(struct AFSFetchStatus)); - OutStats->AFSBulkStats_len = nfiles; - CallBacks->AFSCBs_val = (struct AFSCallBack *) - malloc(nfiles * sizeof(struct AFSCallBack)); - CallBacks->AFSCBs_len = nfiles; - - if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_BulkStatus; - - tfid = Fids->AFSCBFids_val; - for (i=0; idisk.type != vDirectory) { - if ((errorCode = Check_PermissionRights(targetptr, client, rights, - CHK_FETCHSTATUS, 0))) { - if (rx_GetCallAbortCode(acall) == errorCode) - rx_SetCallAbortCode(acall, 0); - goto Bad_BulkStatus; - } - } - - /* set OutStatus From the Fid */ - GetStatus(targetptr, &OutStats->AFSBulkStats_val[i], - rights, anyrights, parentwhentargetnotdir); - - /* If a r/w volume, also set the CallBack state */ - if (VolumeWriteable(volptr)) - SetCallBackStruct(AddBulkCallBack(client->host, tfid), - &CallBacks->AFSCBs_val[i]); - else { - struct AFSFid myFid; - memset(&myFid, 0, sizeof(struct AFSFid)); - myFid.Volume = tfid->Volume; - SetCallBackStruct(AddVolCallBack(client->host, &myFid), - &CallBacks->AFSCBs_val[i]); - } - - /* put back the file ID and volume */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr); - parentwhentargetnotdir = (Vnode *) 0; - targetptr = (Vnode *) 0; - volptr = (Volume *) 0; - } - -Bad_BulkStatus: - /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - CallPostamble(tcon); - -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (errorCode == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } - -#endif /* FS_STATS_DETAILED */ - -Audit_and_Return: - ViceLog(2, ("SAFS_BulkStatus returns %d\n", errorCode)); - osi_auditU (acall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END); - return errorCode; - -} /*SRXAFS_BulkStatus*/ - - -afs_int32 SRXAFS_InlineBulkStatus(struct rx_call *acall, - struct AFSCBFids *Fids, - struct AFSBulkStats *OutStats, - struct AFSCBs *CallBacks, - struct AFSVolSync *Sync) +/* this code should probably just set a "priv" flag where all the audit events + * are now, and only generate the audit event once at the end of the routine, + * thus only generating the event if all the checks succeed, but only because + * of the privilege XXX + */ +static afs_int32 +Check_PermissionRights(Vnode *targetptr, + struct client *client, + afs_int32 rights, + int CallingRoutine, + AFSStoreStatus *InStatus) { - register int i; - afs_int32 nfiles; - Vnode * targetptr = 0; /* pointer to vnode to fetch */ - 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 */ - 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; - AFSFetchStatus *tstatus; -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ - - /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ - - ViceLog(1, ("SAFS_InlineBulkStatus\n")); - FS_LOCK - AFSCallStats.TotalCalls++; - FS_UNLOCK - - nfiles = Fids->AFSCBFids_len; /* # of files in here */ - if (nfiles <= 0) { /* Sanity check */ - errorCode = EINVAL; - goto Audit_and_Return; - } - - /* allocate space for return output parameters */ - OutStats->AFSBulkStats_val = (struct AFSFetchStatus *) - malloc(nfiles * sizeof(struct AFSFetchStatus)); - OutStats->AFSBulkStats_len = nfiles; - CallBacks->AFSCBs_val = (struct AFSCallBack *) - malloc(nfiles * sizeof(struct AFSCallBack)); - CallBacks->AFSCBs_len = nfiles; - - if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) { - goto Bad_InlineBulkStatus; - } - - tfid = Fids->AFSCBFids_val; - for (i=0; iAFSBulkStats_val[i]; - tstatus->errorCode = errorCode; - parentwhentargetnotdir = (Vnode *) 0; - targetptr = (Vnode *) 0; - volptr = (Volume *) 0; - continue; - } - - /* set volume synchronization information, but only once per call */ - if (i == nfiles) - SetVolumeSync(Sync, volptr); - - /* Are we allowed to fetch Fid's status? */ - if (targetptr->disk.type != vDirectory) { - if ((errorCode = Check_PermissionRights(targetptr, client, rights, - CHK_FETCHSTATUS, 0))) { - tstatus = &OutStats->AFSBulkStats_val[i]; - tstatus->errorCode = errorCode; - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr); - parentwhentargetnotdir = (Vnode *) 0; - targetptr = (Vnode *) 0; - volptr = (Volume *) 0; - continue; + int errorCode = 0; +#define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner) +#define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner)) +#define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group)) + + if (CallingRoutine & CHK_FETCH) { +#ifdef CMUCS + if (VanillaUser(client)) +#else + if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client)) +#endif + { + if (targetptr->disk.type == vDirectory || targetptr->disk.type == vSymlink) { + if ( !(rights & PRSFS_LOOKUP) +#ifdef ADMIN_IMPLICIT_LOOKUP + /* grant admins fetch on all directories */ + && VanillaUser(client) +#endif /* ADMIN_IMPLICIT_LOOKUP */ + && !VolumeOwner(client, targetptr)) + return(EACCES); + } else { /* file */ + /* must have read access, or be owner and have insert access */ + if (!(rights & PRSFS_READ) && + !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT))) + return(EACCES); } + if (CallingRoutine == CHK_FETCHDATA && targetptr->disk.type == vFile) +#ifdef USE_GROUP_PERMS + if (!OWNSp(client, targetptr) && + !acl_IsAMember(targetptr->disk.owner, &client->CPS)) { + errorCode = (((GROUPREAD|GROUPEXEC) & targetptr->disk.modeBits) + ? 0: EACCES); + } else { + errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits) + ? 0: EACCES); + } +#else + /* + * The check with the ownership below is a kludge to allow + * reading of files created with no read permission. The owner + * of the file is always allowed to read it. + */ + if ((client->ViceId != targetptr->disk.owner) && VanillaUser(client)) + errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits) ? 0: EACCES); +#endif } - - /* set OutStatus From the Fid */ - GetStatus(targetptr, (struct AFSFetchStatus *) &OutStats->AFSBulkStats_val[i], - rights, anyrights, parentwhentargetnotdir); - - /* If a r/w volume, also set the CallBack state */ - if (VolumeWriteable(volptr)) - SetCallBackStruct(AddBulkCallBack(client->host, tfid), - &CallBacks->AFSCBs_val[i]); - else { - struct AFSFid myFid; - memset(&myFid, 0, sizeof(struct AFSFid)); - myFid.Volume = tfid->Volume; - SetCallBackStruct(AddVolCallBack(client->host, &myFid), - &CallBacks->AFSCBs_val[i]); + else /* !VanillaUser(client) && !FetchData */ { + osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), + AUD_INT, CallingRoutine, AUD_END); } - - /* put back the file ID and volume */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr); - parentwhentargetnotdir = (Vnode *) 0; - targetptr = (Vnode *) 0; - volptr = (Volume *) 0; } - -Bad_InlineBulkStatus: - /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - CallPostamble(tcon); - -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (errorCode == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } - -#endif /* FS_STATS_DETAILED */ - -Audit_and_Return: - ViceLog(2, ("SAFS_InlineBulkStatus returns %d\n", errorCode)); - osi_auditU (acall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END); - return 0; - -} /*SRXAFS_InlineBulkStatus*/ - - -afs_int32 SRXAFS_FetchStatus (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSFetchStatus *OutStatus, - struct AFSCallBack *CallBack, - struct AFSVolSync *Sync) -{ - afs_int32 code; - struct rx_connection *tcon; -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ - - /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ - - if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_FetchStatus; - - code = SAFSS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync); - -Bad_FetchStatus: - CallPostamble(tcon); - -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (code == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } - -#endif /* FS_STATS_DETAILED */ - - osi_auditU (acall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END); - return code; - -} /*SRXAFS_FetchStatus*/ - - -afs_int32 SRXAFS_StoreData (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSStoreStatus *InStatus, - afs_uint32 Pos, - afs_uint32 Length, - afs_uint32 FileLength, - struct AFSFetchStatus *OutStatus, - struct AFSVolSync *Sync) -{ - Vnode * targetptr = 0; /* pointer to input fid */ - Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */ - Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */ - 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 */ - 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 */ - struct rx_connection *tcon; -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval xferStartTime, - xferStopTime; /* Start/stop times for xfer portion*/ - struct timeval elapsedTime; /* Transfer time */ - afs_int32 bytesToXfer; /* # bytes to xfer */ - afs_int32 bytesXferred; /* # bytes actually xfer */ - static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */ - - /* - * Set our stats pointers, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]); - xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - - ViceLog(1, ("StoreData: Fid = %u.%d.%d\n", - Fid->Volume, Fid->Vnode, Fid->Unique)); - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ - - FS_LOCK - AFSCallStats.StoreData++, AFSCallStats.TotalCalls++; - FS_UNLOCK - - if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_StoreData; - - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n", - Fid->Volume, Fid->Vnode, Fid->Unique, - inet_ntoa(logHostAddr), t_client->ViceId)); - - /* - * Get associated volume/vnode for the stored file; caller's rights - * are also returned - */ - if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, - MustNOTBeDIR, &parentwhentargetnotdir, - &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_StoreData; + else { /* a store operation */ + if ( (rights & PRSFS_INSERT) && OWNSp(client, targetptr) + && (CallingRoutine != CHK_STOREACL) + && (targetptr->disk.type == vFile)) + { + /* bypass protection checks on first store after a create + * for the creator; also prevent chowns during this time + * unless you are a system administrator */ + /****** InStatus->Owner && UnixModeBits better be SET!! */ + if ( CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) { + if (readonlyServer) + return(VREADONLY); + else if (VanillaUser (client)) + return(EPERM); /* Was EACCES */ + else + osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), + AUD_INT, CallingRoutine, AUD_END); + } + } else { + if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) { + osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), + AUD_INT, CallingRoutine, AUD_END); + } + else { + if (readonlyServer) { + return(VREADONLY); + } + if (CallingRoutine == CHK_STOREACL) { + if (!(rights & PRSFS_ADMINISTER) && + !VolumeOwner(client, targetptr)) return(EACCES); + } + else { /* store data or status */ + /* watch for chowns and chgrps */ + if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) { + if (readonlyServer) + return(VREADONLY); + else if (VanillaUser (client)) + return(EPERM); /* Was EACCES */ + else + osi_audit(PrivilegeEvent, 0, + AUD_INT, (client ? client->ViceId : 0), + AUD_INT, CallingRoutine, AUD_END); + } + /* must be sysadmin to set suid/sgid bits */ + if ((InStatus->Mask & AFS_SETMODE) && +#ifdef AFS_NT40_ENV + (InStatus->UnixModeBits & 0xc00) != 0) { +#else + (InStatus->UnixModeBits & (S_ISUID|S_ISGID)) != 0) { +#endif + if (readonlyServer) + return(VREADONLY); + if (VanillaUser(client)) + return(EACCES); + else osi_audit( PrivSetID, 0, AUD_INT, (client ? client->ViceId : 0), + AUD_INT, CallingRoutine, AUD_END); + } + if (CallingRoutine == CHK_STOREDATA) { + if (readonlyServer) + return(VREADONLY); + if (!(rights & PRSFS_WRITE)) + return(EACCES); + /* Next thing is tricky. We want to prevent people + * from writing files sans 0200 bit, but we want + * creating new files with 0444 mode to work. We + * don't check the 0200 bit in the "you are the owner" + * path above, but here we check the bit. However, if + * you're a system administrator, we ignore the 0200 + * bit anyway, since you may have fchowned the file, + * too */ +#ifdef USE_GROUP_PERMS + if ((targetptr->disk.type == vFile) + && VanillaUser(client)) { + if (!OWNSp(client, targetptr) && + !acl_IsAMember(targetptr->disk.owner, + &client->CPS)) { + errorCode = ((GROUPWRITE & targetptr->disk.modeBits) + ? 0: EACCES); + } else { + errorCode = ((OWNERWRITE & targetptr->disk.modeBits) + ? 0 : EACCES); + } + } else +#endif + if ((targetptr->disk.type != vDirectory) + && (!(targetptr->disk.modeBits & OWNERWRITE))) + if (readonlyServer) + return(VREADONLY); + if (VanillaUser(client)) + return(EACCES); + else osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), + AUD_INT, CallingRoutine, AUD_END); + } + else { /* a status store */ + if (readonlyServer) + return(VREADONLY); + if (targetptr->disk.type == vDirectory) { + if (!(rights & PRSFS_DELETE) && !(rights & PRSFS_INSERT)) + return(EACCES); + } + else { /* a file or symlink */ + if (!(rights & PRSFS_WRITE)) return(EACCES); + } + } + } + } + } } + return(errorCode); - /* set volume synchronization information */ - SetVolumeSync(Sync, volptr); +} /*Check_PermissionRights*/ - if ((targetptr->disk.type == vSymlink)) { - /* Should we return a better error code here??? */ - errorCode = EISDIR; - goto Bad_StoreData; - } - /* Check if we're allowed to store the data */ - if ((errorCode = Check_PermissionRights(targetptr, client, rights, - CHK_STOREDATA, InStatus))) { - goto Bad_StoreData; - } +/* + * The Access List information is converted from its internal form in the + * target's vnode buffer (or its parent vnode buffer if not a dir), to an + * external form and returned back to the caller, via the AccessList + * structure + */ +static afs_int32 +RXFetch_AccessList(Vnode *targetptr, + Vnode *parentwhentargetnotdir, + struct AFSOpaque *AccessList) +{ + char * eACL; /* External access list placeholder */ - /* - * Drop the read lock on the parent directory after saving the parent - * vnode information we need to pass to GetStatus - */ - if (parentwhentargetnotdir != NULL) { - tparentwhentargetnotdir = *parentwhentargetnotdir; - VPutVnode(&fileCode, parentwhentargetnotdir); - assert(!fileCode || (fileCode == VSALVAGE)); - parentwhentargetnotdir = NULL; + if (acl_Externalize((targetptr->disk.type == vDirectory ? + VVnodeACL(targetptr) : + VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) { + return EIO; } - - - -#if FS_STATS_DETAILED - /* - * Remember when the data transfer started. - */ - TM_GetTimeOfDay(&xferStartTime, 0); -#endif /* FS_STATS_DETAILED */ - - /* Do the actual storing of the data */ -#if FS_STATS_DETAILED - errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, acall, - Pos, Length, FileLength, - (InStatus->Mask & AFS_FSYNC), - &bytesToXfer, &bytesXferred); -#else - errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, - acall, Pos, Length, FileLength, - (InStatus->Mask & AFS_FSYNC)); - if (errorCode && (!targetptr->changed_newTime)) - goto Bad_StoreData; -#endif /* FS_STATS_DETAILED */ -#if FS_STATS_DETAILED - /* - * At this point, the data transfer is done, for good or ill. Remember - * when the transfer ended, bump the number of successes/failures, and - * integrate the transfer size and elapsed time into the stats. If the - * operation failed, we jump to the appropriate point. - */ - TM_GetTimeOfDay(&xferStopTime, 0); - FS_LOCK - (xferP->numXfers)++; - if (!errorCode) { - (xferP->numSuccesses)++; - - /* - * Bump the xfer sum by the number of bytes actually sent, NOT the - * target number. - */ - tot_bytesXferred += bytesXferred; - (xferP->sumBytes) += (tot_bytesXferred >> 10); - tot_bytesXferred &= 0x3FF; - if (bytesXferred < xferP->minBytes) - xferP->minBytes = bytesXferred; - if (bytesXferred > xferP->maxBytes) - xferP->maxBytes = bytesXferred; - - /* - * Tally the size of the object. Note: we tally the actual size, - * NOT the number of bytes that made it out over the wire. - */ - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0) - (xferP->count[0])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1) - (xferP->count[1])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2) - (xferP->count[2])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3) - (xferP->count[3])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4) - (xferP->count[4])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5) - (xferP->count[5])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6) - (xferP->count[6])++; - else - if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7) - (xferP->count[7])++; - else - (xferP->count[8])++; - - fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime); - fs_stats_AddTo((xferP->sumTime), elapsedTime); - fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) { - fs_stats_TimeAssign((xferP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) { - fs_stats_TimeAssign((xferP->maxTime), elapsedTime); - } + if ((strlen(eACL)+1) > AFSOPAQUEMAX) { + acl_FreeExternalACL(&eACL); + return(E2BIG); + } else { + strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL); + AccessList->AFSOpaque_len = strlen(eACL) +1; } - FS_UNLOCK - - /* - * Finally, go off to tell our caller the bad news in case the - * store failed. - */ - if (errorCode && (!targetptr->changed_newTime)) - goto Bad_StoreData; -#endif /* FS_STATS_DETAILED */ - - /* Update the status of the target's vnode */ - Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr, - volptr, 0); - - /* Get the updated File's status back to the caller */ - GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir); + acl_FreeExternalACL(&eACL); + return(0); -Bad_StoreData: - /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode)); +} /*RXFetch_AccessList*/ - CallPostamble(tcon); -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (errorCode == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } -#endif /* FS_STATS_DETAILED */ +/* + * The Access List information is converted from its external form in the + * input AccessList structure to the internal representation and copied into + * the target dir's vnode storage. + */ +static afs_int32 +RXStore_AccessList(Vnode *targetptr, struct AFSOpaque *AccessList) +{ + struct acl_accessList * newACL; /* PlaceHolder for new access list */ - osi_auditU (acall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END); - return(errorCode); + if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0) + return(EINVAL); + if ((newACL->size + 4) > VAclSize(targetptr)) + return(E2BIG); + memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size)); + acl_FreeACL(&newACL); + return(0); -} /*SRXAFS_StoreData*/ +} /*RXStore_AccessList*/ -afs_int32 SRXAFS_StoreData64 (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSStoreStatus *InStatus, - afs_uint64 Pos, - afs_uint64 Length, - afs_uint64 FileLength, - struct AFSFetchStatus *OutStatus, - struct AFSVolSync *Sync) + +static afs_int32 +Fetch_AccessList(Vnode *targetptr, Vnode *parentwhentargetnotdir, + struct AFSAccessList *AccessList) { - int code; - afs_int32 tPos; - afs_int32 tLength; - afs_int32 tFileLength; + char * eACL; /* External access list placeholder */ -#ifdef AFS_64BIT_ENV - if (FileLength > 0x7fffffff) - return E2BIG; - tPos = Pos; - tLength = Length; - tFileLength = FileLength; -#else /* AFS_64BIT_ENV */ - if (FileLength.high) - return E2BIG; - tPos = Pos.low; - tLength = Length.low; - tFileLength = FileLength.low; -#endif /* AFS_64BIT_ENV */ + assert(acl_Externalize((targetptr->disk.type == vDirectory ? + VVnodeACL(targetptr) : + VVnodeACL(parentwhentargetnotdir)), &eACL) == 0); + if ((strlen(eACL)+1) > AccessList->MaxSeqLen) { + acl_FreeExternalACL(&eACL); + return(E2BIG); + } else { + strcpy((char *)(AccessList->SeqBody), (char *)eACL); + AccessList->SeqLen = strlen(eACL) +1; + } + acl_FreeExternalACL(&eACL); + return(0); - code = SRXAFS_StoreData (acall, Fid, InStatus, tPos, tLength, tFileLength, - OutStatus, Sync); - return code; -} +} /*Fetch_AccessList*/ -afs_int32 SRXAFS_StoreACL (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSOpaque *AccessList, - struct AFSFetchStatus *OutStatus, - struct AFSVolSync *Sync) +/* + * The Access List information is converted from its external form in the + * input AccessList structure to the internal representation and copied into + * the target dir's vnode storage. + */ +static afs_int32 +Store_AccessList(Vnode *targetptr, struct AFSAccessList *AccessList) { - Vnode * targetptr = 0; /* pointer to input fid */ - Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */ - 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 */ - afs_int32 rights, anyrights; /* rights for this and any user */ - struct rx_connection *tcon; - struct client *t_client; /* tmp ptr to client data */ - struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ + struct acl_accessList * newACL; /* PlaceHolder for new access list */ - /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ - if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_StoreACL; + if (acl_Internalize(AccessList->SeqBody, &newACL) != 0) + return(EINVAL); + if ((newACL->size + 4) > VAclSize(targetptr)) + return(E2BIG); + memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size)); + acl_FreeACL(&newACL); + return(0); - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n", - Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val, - inet_ntoa(logHostAddr), t_client->ViceId)); - FS_LOCK - AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++; - FS_UNLOCK +} /*Store_AccessList*/ - InStatus.Mask = 0; /* not storing any status */ - /* - * Get associated volume/vnode for the target dir; caller's rights - * are also returned. - */ - if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, - MustBeDIR, &parentwhentargetnotdir, - &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_StoreACL; +/* In our current implementation, each successive data store (new file + * data version) creates a new inode. This function creates the new + * inode, copies the old inode's contents to the new one, remove the old + * inode (i.e. decrement inode count -- if it's currently used the delete + * will be delayed), and modify some fields (i.e. vnode's + * disk.inodeNumber and cloned) + */ +#define COPYBUFFSIZE 8192 +static int CopyOnWrite(Vnode *targetptr, Volume *volptr) +{ + Inode ino, nearInode; + int rdlen; + int wrlen; + register int size, length; + int ifd, ofd; + char *buff; + int rc; /* return code */ + IHandle_t *newH; /* Use until finished copying, then cp to vnode.*/ + FdHandle_t *targFdP; /* Source Inode file handle */ + FdHandle_t *newFdP; /* Dest Inode file handle */ + + if (targetptr->disk.type == vDirectory) DFlush(); /* just in case? */ + + size = targetptr->disk.length; + buff = (char *)malloc(COPYBUFFSIZE); + if (buff == NULL) { + return EIO; + } + + ino = VN_GET_INO(targetptr); + assert(VALID_INO(ino)); + targFdP = IH_OPEN(targetptr->handle); + if (targFdP == NULL) { + rc = errno; + ViceLog(0, ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n", targetptr->vnodeNumber, V_id(volptr), rc)); + free(buff); + VTakeOffline (volptr); + return rc; + } + + nearInode = VN_GET_INO(targetptr); + ino = IH_CREATE(V_linkHandle(volptr), V_device(volptr), + VPartitionPath(V_partition(volptr)),nearInode, V_id(volptr), + targetptr->vnodeNumber, targetptr->disk.uniquifier, + (int)targetptr->disk.dataVersion); + if (!VALID_INO(ino)) + { + ViceLog(0,("CopyOnWrite failed: Partition %s that contains volume %u may be out of free inodes(errno = %d)\n", volptr->partition->name, V_id(volptr), errno)); + FDH_CLOSE(targFdP); + free(buff); + return ENOSPC; + } + IH_INIT(newH, V_device(volptr), V_id(volptr), ino); + newFdP = IH_OPEN(newH); + assert(newFdP != NULL); + + while(size > 0) { + if (size > COPYBUFFSIZE) { /* more than a buffer */ + length = COPYBUFFSIZE; + size -= COPYBUFFSIZE; + } else { + length = size; + size = 0; + } + rdlen = FDH_READ(targFdP, buff, length); + if (rdlen == length) + wrlen = FDH_WRITE(newFdP, buff, length); + else + wrlen = 0; + /* Callers of this function are not prepared to recover + * from error that put the filesystem in an inconsistent + * state. Make sure that we force the volume off-line if + * we some error other than ENOSPC - 4.29.99) + * + * In case we are unable to write the required bytes, and the + * error code indicates that the disk is full, we roll-back to + * the initial state. + */ + if((rdlen != length) || (wrlen != length)) + if ( (wrlen < 0) && (errno == ENOSPC) ) /* disk full */ + { + ViceLog(0,("CopyOnWrite failed: Partition %s containing volume %u is full\n", + volptr->partition->name, V_id(volptr))); + /* remove destination inode which was partially copied till now*/ + FDH_REALLYCLOSE(newFdP); + IH_RELEASE(newH); + FDH_REALLYCLOSE(targFdP); + rc = IH_DEC(V_linkHandle(volptr), ino, + V_parentId(volptr)); + if (!rc ) { + ViceLog(0,("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n", + rc, V_id(volptr), + volptr->partition->name)); + VTakeOffline (volptr); + } + free(buff); + return ENOSPC; + } + else { + ViceLog(0,("CopyOnWrite failed: volume %u in partition %s (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n", + V_id(volptr), volptr->partition->name, length, + rdlen, wrlen, errno)); +#ifdef FAST_RESTART /* if running in no-salvage, don't core the server */ + ViceLog(0,("CopyOnWrite failed: taking volume offline\n")); +#else /* Avoid further corruption and try to get a core. */ + assert(0); +#endif + /* Decrement this inode so salvager doesn't find it. */ + FDH_REALLYCLOSE(newFdP); + IH_RELEASE(newH); + FDH_REALLYCLOSE(targFdP); + rc = IH_DEC(V_linkHandle(volptr), ino, + V_parentId(volptr)); + free(buff); + VTakeOffline (volptr); + return EIO; + } +#ifndef AFS_PTHREAD_ENV + IOMGR_Poll(); +#endif /* !AFS_PTHREAD_ENV */ } + FDH_REALLYCLOSE(targFdP); + rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr), + V_parentId(volptr)) ; + assert(!rc); + IH_RELEASE(targetptr->handle); + + rc = FDH_SYNC(newFdP); + assert(rc == 0); + FDH_CLOSE(newFdP); + targetptr->handle = newH; + VN_SET_INO(targetptr, ino); + targetptr->disk.cloned = 0; + /* Internal change to vnode, no user level change to volume - def 5445 */ + targetptr->changed_oldTime = 1; + free(buff); + return 0; /* success */ +} /*CopyOnWrite*/ - /* set volume synchronization information */ - SetVolumeSync(Sync, volptr); - /* Check if we have permission to change the dir's ACL */ - if ((errorCode = Check_PermissionRights(targetptr, client, rights, - CHK_STOREACL, &InStatus))) { - goto Bad_StoreACL; - } +/* + * Common code to handle with removing the Name (file when it's called from + * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a + * given directory, parentptr. + */ +int DT1=0, DT0=0; +static afs_int32 +DeleteTarget(Vnode *parentptr, + Volume *volptr, + Vnode **targetptr, + DirHandle *dir, + AFSFid *fileFid, + char *Name, + int ChkForDir) +{ + DirHandle childdir; /* Handle for dir package I/O */ + int errorCode = 0; + int code; - /* Build and store the new Access List for the dir */ - if ((errorCode = RXStore_AccessList(targetptr, AccessList))) { - goto Bad_StoreACL; + /* watch for invalid names */ + if (!strcmp(Name, ".") || !strcmp(Name, "..")) + return (EINVAL); + if (parentptr->disk.cloned) + { + ViceLog(25, ("DeleteTarget : CopyOnWrite called\n")); + if ((errorCode = CopyOnWrite(parentptr, volptr))) + { + ViceLog(20, ("DeleteTarget %s: CopyOnWrite failed %d\n",Name,errorCode)); + return errorCode; + } } - - targetptr->changed_newTime = 1; /* status change of directory */ - - /* convert the write lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, targetptr); - assert(!errorCode || errorCode == VSALVAGE); - /* break call backs on the directory */ - BreakCallBack(client->host, Fid, 0); + /* check that the file is in the directory */ + SetDirHandle(dir, parentptr); + if (Lookup(dir, Name, fileFid)) + return(ENOENT); + fileFid->Volume = V_id(volptr); - /* Get the updated dir's status back to the caller */ - GetStatus(targetptr, OutStatus, rights, anyrights, 0); + /* just-in-case check for something causing deadlock */ + if (fileFid->Vnode == parentptr->vnodeNumber) + return(EINVAL); -Bad_StoreACL: - /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode)); - CallPostamble(tcon); + *targetptr = VGetVnode(&errorCode, volptr, fileFid->Vnode, WRITE_LOCK); + if (errorCode) { + return (errorCode); + } + if (ChkForDir == MustBeDIR) { + if ((*targetptr)->disk.type != vDirectory) + return(ENOTDIR); + } else if ((*targetptr)->disk.type == vDirectory) + return(EISDIR); + + /*assert((*targetptr)->disk.uniquifier == fileFid->Unique);*/ + /** + * If the uniquifiers dont match then instead of asserting + * take the volume offline and return VSALVAGE + */ + if ( (*targetptr)->disk.uniquifier != fileFid->Unique ) { + VTakeOffline(volptr); + errorCode = VSALVAGE; + return errorCode; + } + + if (ChkForDir == MustBeDIR) { + SetDirHandle(&childdir, *targetptr); + if (IsEmpty(&childdir) != 0) + return(EEXIST); + DZap(&childdir); + (*targetptr)->delete = 1; + } else if ((--(*targetptr)->disk.linkCount) == 0) + (*targetptr)->delete = 1; + if ((*targetptr)->delete) { + if (VN_GET_INO(*targetptr)) { + DT0++; + IH_REALLYCLOSE((*targetptr)->handle); + errorCode = IH_DEC(V_linkHandle(volptr), + VN_GET_INO(*targetptr), + V_parentId(volptr)); + IH_RELEASE((*targetptr)->handle); + if (errorCode == -1) { + ViceLog(0, ("DT: inode=%s, name=%s, errno=%d\n", + PrintInode(NULL, VN_GET_INO(*targetptr)), + Name, errno)); +#ifdef AFS_DEC_ENV + if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO)) +#else + if (errno != ENOENT) +#endif + { + ViceLog(0, ("Volume %u now offline, must be salvaged.\n", + volptr->hashid)); + VTakeOffline(volptr); + return (EIO); + } + DT1++; + errorCode = 0; + } + } + VN_SET_INO(*targetptr, (Inode)0); + VAdjustDiskUsage(&errorCode, volptr, + -(int)nBlocks((*targetptr)->disk.length), 0); + } + + (*targetptr)->changed_newTime = 1; /* Status change of deleted file/dir */ -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (errorCode == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK + code = Delete(dir,(char *) Name); + if (code) { + ViceLog(0, ("Error %d deleting %s\n", code, + (((*targetptr)->disk.type== Directory)?"directory":"file"))); + ViceLog(0, ("Volume %u now offline, must be salvaged.\n", + volptr->hashid)); + VTakeOffline(volptr); + if (!errorCode) errorCode = code; } -#endif /* FS_STATS_DETAILED */ - osi_auditU (acall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END); - return errorCode; + DFlush(); + return(errorCode); -} /*SRXAFS_StoreACL*/ +} /*DeleteTarget*/ /* - * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and - * should be merged when possible. + * This routine updates the parent directory's status block after the + * specified operation (i.e. RemoveFile(), CreateFile(), Rename(), + * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has + * been performed. */ -static afs_int32 -SAFSS_StoreStatus (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSStoreStatus *InStatus, - struct AFSFetchStatus *OutStatus, - struct AFSVolSync *Sync) - +static void +Update_ParentVnodeStatus(Vnode *parentptr, + Volume *volptr, + DirHandle *dir, + int author, + int linkcount, +#if FS_STATS_DETAILED + char a_inSameNetwork +#endif /* FS_STATS_DETAILED */ + ) { - Vnode * targetptr = 0; /* pointer to input 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 */ - 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 */ - struct rx_connection *tcon = rx_ConnectionOf(acall); + afs_uint32 newlength; /* Holds new directory length */ + int errorCode; +#if FS_STATS_DETAILED + Date currDate; /*Current date*/ + int writeIdx; /*Write index to bump*/ + int timeIdx; /*Authorship time index to bump*/ +#endif /* FS_STATS_DETAILED */ - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1, ("SAFS_StoreStatus, Fid = %u.%d.%d, Host %s, Id %d\n", - Fid->Volume, Fid->Vnode, Fid->Unique, - inet_ntoa(logHostAddr), t_client->ViceId)); - FS_LOCK - AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++; - FS_UNLOCK + parentptr->disk.dataVersion++; + newlength = Length(dir); + /* + * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions + * (create, symlink, link, makedir) so we need to check if we have enough space + * XXX But we still don't check the error since we're dealing with dirs here and really the increase + * of a new entry would be too tiny to worry about failures (since we have all the existing cushion) + */ + if (nBlocks(newlength) != nBlocks(parentptr->disk.length)) + VAdjustDiskUsage(&errorCode, volptr, + (int)(nBlocks(newlength) - nBlocks(parentptr->disk.length)), + (int)(nBlocks(newlength) - nBlocks(parentptr->disk.length))); + parentptr->disk.length = newlength; + +#if FS_STATS_DETAILED /* - * Get volume/vnode for the target file; caller's rights to it are - * also returned + * Update directory write stats for this volume. Note that the auth + * counter is located immediately after its associated ``distance'' + * counter. */ - if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, - DONTCHECK, &parentwhentargetnotdir, - &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_StoreStatus; + if (a_inSameNetwork) + writeIdx = VOL_STATS_SAME_NET; + else + writeIdx = VOL_STATS_DIFF_NET; + V_stat_writes(volptr, writeIdx)++; + if (author != AnonymousID) { + V_stat_writes(volptr, writeIdx+1)++; + } + + /* + * Update the volume's authorship information in response to this + * directory operation. Get the current time, decide to which time + * slot this operation belongs, and bump the appropriate slot. + */ + currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime); + timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : + currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : + currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : + currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : + currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 : + VOL_STATS_TIME_IDX_5); + if (parentptr->disk.author == author) { + V_stat_dirSameAuthor(volptr, timeIdx)++; + } + else { + V_stat_dirDiffAuthor(volptr, timeIdx)++; } +#endif /* FS_STATS_DETAILED */ - /* set volume synchronization information */ - SetVolumeSync(Sync, volptr); + parentptr->disk.author = author; + parentptr->disk.linkCount = linkcount; + parentptr->disk.unixModifyTime = FT_ApproxTime(); /* This should be set from CLIENT!! */ + parentptr->disk.serverModifyTime = FT_ApproxTime(); + parentptr->changed_newTime = 1; /* vnode changed, write it back. */ +} - /* Check if the caller has proper permissions to store status to Fid */ - if ((errorCode = Check_PermissionRights(targetptr, client, rights, - CHK_STORESTATUS, InStatus))) { - goto Bad_StoreStatus; + +/* + * Update the target file's (or dir's) status block after the specified + * operation is complete. Note that some other fields maybe updated by + * the individual module. + */ + +/* XXX INCOMPLETE - More attention is needed here! */ +static void +Update_TargetVnodeStatus(Vnode *targetptr, + afs_uint32 Caller, + struct client *client, + AFSStoreStatus *InStatus, + Vnode *parentptr, + Volume *volptr, + afs_int32 length) +{ +#if FS_STATS_DETAILED + Date currDate; /*Current date*/ + int writeIdx; /*Write index to bump*/ + int timeIdx; /*Authorship time index to bump*/ +#endif /* FS_STATS_DETAILED */ + + if (Caller & (TVS_CFILE|TVS_SLINK|TVS_MKDIR)) { /* initialize new file */ + targetptr->disk.parent = parentptr->vnodeNumber; + targetptr->disk.length = length; + /* targetptr->disk.group = 0; save some cycles */ + targetptr->disk.modeBits = 0777; + targetptr->disk.owner = client->ViceId; + targetptr->disk.dataVersion = 0 ; /* consistent with the client */ + targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1); + /* the inode was created in Alloc_NewVnode() */ } + +#if FS_STATS_DETAILED /* - * Check for a symbolic link; we can't chmod these (otherwise could - * change a symlink to a mt pt or vice versa) + * Update file write stats for this volume. Note that the auth + * counter is located immediately after its associated ``distance'' + * counter. */ - if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) { - errorCode = EINVAL; - goto Bad_StoreStatus; + if (client->InSameNetwork) + writeIdx = VOL_STATS_SAME_NET; + else + writeIdx = VOL_STATS_DIFF_NET; + V_stat_writes(volptr, writeIdx)++; + if (client->ViceId != AnonymousID) { + V_stat_writes(volptr, writeIdx+1)++; } - /* Update the status of the target's vnode */ - Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus, - (parentwhentargetnotdir ? - parentwhentargetnotdir : targetptr), volptr, 0); - - /* convert the write lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, targetptr); - assert(!errorCode || errorCode == VSALVAGE); - - /* Break call backs on Fid */ - BreakCallBack(client->host, Fid, 0); + /* + * We only count operations that DON'T involve creating new objects + * (files, symlinks, directories) or simply setting status as + * authorship-change operations. + */ + if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) { + /* + * Update the volume's authorship information in response to this + * file operation. Get the current time, decide to which time + * slot this operation belongs, and bump the appropriate slot. + */ + currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime); + timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : + currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : + currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : + currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : + currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 : + VOL_STATS_TIME_IDX_5); + if (targetptr->disk.author == client->ViceId) { + V_stat_fileSameAuthor(volptr, timeIdx)++; + } else { + V_stat_fileDiffAuthor(volptr, timeIdx)++; + } + } +#endif /* FS_STATS_DETAILED */ - /* Return the updated status back to caller */ - GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir); + if (!(Caller & TVS_SSTATUS)) + targetptr->disk.author = client->ViceId; + if (Caller & TVS_SDATA) { + targetptr->disk.dataVersion++; + if (VanillaUser(client)) + { + targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */ +#ifdef CREATE_SGUID_ADMIN_ONLY + targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */ +#endif + } + } + if (Caller & TVS_SSTATUS) { /* update time on non-status change */ + /* store status, must explicitly request to change the date */ + if (InStatus->Mask & AFS_SETMODTIME) + targetptr->disk.unixModifyTime = InStatus->ClientModTime; + } + else {/* other: date always changes, but perhaps to what is specified by caller */ + targetptr->disk.unixModifyTime = (InStatus->Mask & AFS_SETMODTIME ? InStatus->ClientModTime : FT_ApproxTime()); + } + if (InStatus->Mask & AFS_SETOWNER) { + /* admin is allowed to do chmod, chown as well as chown, chmod. */ + if (VanillaUser(client)) + { + targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */ +#ifdef CREATE_SGUID_ADMIN_ONLY + targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */ +#endif + } + targetptr->disk.owner = InStatus->Owner; + if (VolumeRootVnode (targetptr)) { + Error errorCode = 0; /* what should be done with this? */ -Bad_StoreStatus: - /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode)); - return errorCode; + V_owner(targetptr->volumePtr) = InStatus->Owner; + VUpdateVolume(&errorCode, targetptr->volumePtr); + } + } + if (InStatus->Mask & AFS_SETMODE) { + int modebits = InStatus->UnixModeBits; +#define CREATE_SGUID_ADMIN_ONLY 1 +#ifdef CREATE_SGUID_ADMIN_ONLY + if (VanillaUser(client)) + modebits = modebits & 0777; +#endif + if (VanillaUser(client)) { + targetptr->disk.modeBits = modebits; + } + else { + targetptr->disk.modeBits = modebits; + switch ( Caller ) { + case TVS_SDATA: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId, + AUD_INT, CHK_STOREDATA, AUD_END); break; + case TVS_CFILE: + case TVS_SSTATUS: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId, + AUD_INT, CHK_STORESTATUS, AUD_END); break; + default: break; + } + } + } + targetptr->disk.serverModifyTime = FT_ApproxTime(); + if (InStatus->Mask & AFS_SETGROUP) + targetptr->disk.group = InStatus->Group; + /* vnode changed : to be written back by VPutVnode */ + targetptr->changed_newTime = 1; -} /*SAFSS_StoreStatus*/ +} /*Update_TargetVnodeStatus*/ -afs_int32 SRXAFS_StoreStatus (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSStoreStatus *InStatus, - struct AFSFetchStatus *OutStatus, - struct AFSVolSync *Sync) +/* + * Fills the CallBack structure with the expiration time and type of callback + * structure. Warning: this function is currently incomplete. + */ +static void +SetCallBackStruct(afs_uint32 CallBackTime, struct AFSCallBack *CallBack) { - afs_int32 code; - struct rx_connection *tcon; -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ - - /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ + /* CallBackTime could not be 0 */ + if (CallBackTime == 0) { + ViceLog(0, ("WARNING: CallBackTime == 0!\n")); + CallBack->ExpirationTime = 0; + } else + CallBack->ExpirationTime = CallBackTime - FT_ApproxTime(); + CallBack->CallBackVersion = CALLBACK_VERSION; + CallBack->CallBackType = CB_SHARED; /* The default for now */ - if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_StoreStatus; +} /*SetCallBackStruct*/ - code = SAFSS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync); -Bad_StoreStatus: - CallPostamble(tcon); +/* + * Adjusts (Subtract) "length" number of blocks from the volume's disk + * allocation; if some error occured (exceeded volume quota or partition + * was full, or whatever), it frees the space back and returns the code. + * We usually pre-adjust the volume space to make sure that there's + * enough space before consuming some. + */ +static afs_int32 +AdjustDiskUsage(Volume *volptr, afs_int32 length, afs_int32 checkLength) +{ + int rc; + int nc; -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (code == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK + VAdjustDiskUsage(&rc, volptr, length, checkLength); + if (rc) { + VAdjustDiskUsage(&nc, volptr, -length, 0); + if (rc == VOVERQUOTA) { + ViceLog(2,("Volume %u (%s) is full\n", + V_id(volptr), V_name(volptr))); + return(rc); + } + if (rc == VDISKFULL) { + ViceLog(0,("Partition %s that contains volume %u is full\n", + volptr->partition->name, V_id(volptr))); + return(rc); + } + ViceLog(0,("Got error return %d from VAdjustDiskUsage\n",rc)); + return(rc); } + return(0); -#endif /* FS_STATS_DETAILED */ - - osi_auditU (acall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END); - return code; - -} /*SRXAFS_StoreStatus*/ - +} /*AdjustDiskUsage*/ /* - * This routine is called exclusively by SRXAFS_RemoveFile(), and should be - * merged in when possible. + * Common code that handles the creation of a new file (SAFS_CreateFile and + * SAFS_Symlink) or a new dir (SAFS_MakeDir) */ static afs_int32 -SAFSS_RemoveFile (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - struct AFSFetchStatus *OutDirStatus, - struct AFSVolSync *Sync) +Alloc_NewVnode(Vnode *parentptr, + DirHandle *dir, + Volume *volptr, + Vnode **targetptr, + char *Name, + struct AFSFid *OutFid, + int FileType, + int BlocksPreallocatedForVnode) { - Vnode * parentptr = 0; /* vnode of input Directory */ - Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ - Vnode * targetptr = 0; /* file to be deleted */ - Volume * volptr = 0; /* pointer to the volume header */ - 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 */ - 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 */ - struct rx_connection *tcon = rx_ConnectionOf(acall); + int errorCode = 0; /* Error code returned back */ + int temp; + Inode inode=0; + Inode nearInode; /* hint for inode allocation in solaris */ - FidZero(&dir); - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1, ("SAFS_RemoveFile %s, Did = %u.%d.%d, Host %s, Id %d\n", - Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique, - inet_ntoa(logHostAddr), t_client->ViceId)); - FS_LOCK - AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++; - FS_UNLOCK - /* - * Get volume/vnode for the parent dir; caller's access rights are - * also returned - */ - if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, - MustBeDIR, &parentwhentargetnotdir, - &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_RemoveFile; + if ((errorCode = AdjustDiskUsage(volptr, BlocksPreallocatedForVnode, + BlocksPreallocatedForVnode))) { + ViceLog(25, ("Insufficient space to allocate %d blocks\n", + BlocksPreallocatedForVnode)); + return(errorCode); } - /* set volume synchronization information */ - SetVolumeSync(Sync, volptr); - /* Does the caller has delete (& write) access to the parent directory? */ - if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) { - goto Bad_RemoveFile; + *targetptr = VAllocVnode(&errorCode, volptr, FileType); + if (errorCode != 0) { + VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode, 0); + return(errorCode); } + OutFid->Volume = V_id(volptr); + OutFid->Vnode = (*targetptr)->vnodeNumber; + OutFid->Unique = (*targetptr)->disk.uniquifier; - /* Actually delete the desired file */ - if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, - &fileFid, Name, MustNOTBeDIR))) { - goto Bad_RemoveFile; - } + nearInode = VN_GET_INO(parentptr); /* parent is also in same vol */ - /* Update the vnode status of the parent dir */ -#if FS_STATS_DETAILED - Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, - parentptr->disk.linkCount, client->InSameNetwork); -#else - Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, - parentptr->disk.linkCount); -#endif /* FS_STATS_DETAILED */ + /* create the inode now itself */ + inode = IH_CREATE(V_linkHandle(volptr), V_device(volptr), + VPartitionPath(V_partition(volptr)), nearInode, + V_id(volptr), (*targetptr)->vnodeNumber, + (*targetptr)->disk.uniquifier, 1); - /* Return the updated parent dir's status back to caller */ - GetStatus(parentptr, OutDirStatus, rights, anyrights, 0); + /* error in creating inode */ + if (!VALID_INO(inode)) + { + ViceLog(0, ("Volume : %d vnode = %d Failed to create inode: errno = %d\n", + (*targetptr)->volumePtr->header->diskstuff.id, + (*targetptr)->vnodeNumber, + errno)); + VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode,0); + (*targetptr)->delete = 1; /* delete vnode */ + return ENOSPC; + } + VN_SET_INO(*targetptr, inode); + IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode); - /* Handle internal callback state for the parent and the deleted file */ - if (targetptr->disk.linkCount == 0) { - /* no references left, discard entry */ - DeleteFileCallBacks(&fileFid); - /* convert the parent lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, parentptr); - assert(!errorCode || errorCode == VSALVAGE); - } else { - /* convert the parent lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, parentptr); - assert(!errorCode || errorCode == VSALVAGE); - /* convert the target lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, targetptr); - assert(!errorCode || errorCode == VSALVAGE); - /* tell all the file has changed */ - BreakCallBack(client->host, &fileFid, 1); + /* copy group from parent dir */ + (*targetptr)->disk.group = parentptr->disk.group; + + if (parentptr->disk.cloned) + { + ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n")); + if ((errorCode = CopyOnWrite(parentptr, volptr))) /* disk full */ + { + ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n")); + /* delete the vnode previously allocated */ + (*targetptr)->delete = 1; + VAdjustDiskUsage(&temp, volptr, + -BlocksPreallocatedForVnode, 0); + IH_REALLYCLOSE((*targetptr)->handle); + if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)) ) + ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n", + volptr->partition->name, + PrintInode(NULL, inode))); + IH_RELEASE((*targetptr)->handle); + + return errorCode; + } + } + + /* add the name to the directory */ + SetDirHandle(dir, parentptr); + if ((errorCode = Create(dir,(char *)Name, OutFid))) { + (*targetptr)->delete = 1; + VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode, 0); + IH_REALLYCLOSE((*targetptr)->handle); + if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr))) + ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n", + volptr->partition->name, + PrintInode(NULL, inode))); + IH_RELEASE((*targetptr)->handle); + return(errorCode); } + DFlush(); + return(0); - /* break call back on the directory */ - BreakCallBack(client->host, DirFid, 0); +} /*Alloc_NewVnode*/ -Bad_RemoveFile: - /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); - FidZap(&dir); - ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode)); - return errorCode; -} /*SAFSS_RemoveFile*/ +/* + * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and + * SAFS_ReleaseLock) + */ +static afs_int32 +HandleLocking(Vnode *targetptr, afs_int32 rights, ViceLockType LockingType) +{ + int Time; /* Used for time */ + int writeVnode = targetptr->changed_oldTime; /* save original status */ + + /* Does the caller has Lock priviledges; root extends locks, however */ + if (LockingType != LockExtend && !(rights & PRSFS_LOCK)) + return(EACCES); + targetptr->changed_oldTime = 1; /* locking doesn't affect any time stamp */ + Time = FT_ApproxTime(); + switch (LockingType) { + case LockRead: + case LockWrite: + if (Time > targetptr->disk.lock.lockTime) + targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount = 0; + Time += AFS_LOCKWAIT; + if (LockingType == LockRead) { + if (targetptr->disk.lock.lockCount >= 0) { + ++(targetptr->disk.lock.lockCount); + targetptr->disk.lock.lockTime = Time; + } else return(EAGAIN); + } else { + if (targetptr->disk.lock.lockCount == 0) { + targetptr->disk.lock.lockCount = -1; + targetptr->disk.lock.lockTime = Time; + } else return(EAGAIN); + } + break; + case LockExtend: + Time += AFS_LOCKWAIT; + if (targetptr->disk.lock.lockCount != 0) + targetptr->disk.lock.lockTime = Time; + else return(EINVAL); + break; + case LockRelease: + if ((--targetptr->disk.lock.lockCount) <= 0) + targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime = 0; + break; + default: + targetptr->changed_oldTime = writeVnode; /* restore old status */ + ViceLog(0, ("Illegal Locking type %d\n", LockingType)); + } + return(0); +} /*HandleLocking*/ +/* Checks if caller has the proper AFS and Unix (WRITE) access permission to the target directory; Prfs_Mode refers to the AFS Mode operation while rights contains the caller's access permissions to the directory. */ -afs_int32 SRXAFS_RemoveFile (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - struct AFSFetchStatus *OutDirStatus, - struct AFSVolSync *Sync) +static afs_int32 +CheckWriteMode(Vnode *targetptr, afs_int32 rights, int Prfs_Mode) { - afs_int32 code; - struct rx_connection *tcon; -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ + if (readonlyServer) + return(VREADONLY); + if (!(rights & Prfs_Mode)) + return(EACCES); + if ((targetptr->disk.type != vDirectory) && (!(targetptr->disk.modeBits & OWNERWRITE))) + return(EACCES); + return(0); +} + +/* + * If some flags (i.e. min or max quota) are set, the volume's in disk + * label is updated; Name, OfflineMsg, and Motd are also reflected in the + * update, if applicable. + */ +static afs_int32 +RXUpdate_VolumeStatus(Volume *volptr, AFSStoreVolumeStatus* StoreVolStatus, + char *Name, char *OfflineMsg, char *Motd) +{ + Error errorCode = 0; + if (StoreVolStatus->Mask & AFS_SETMINQUOTA) + V_minquota(volptr) = StoreVolStatus->MinQuota; + if (StoreVolStatus->Mask & AFS_SETMAXQUOTA) + V_maxquota(volptr) = StoreVolStatus->MaxQuota; + if (strlen(OfflineMsg) > 0) { + strcpy(V_offlineMessage(volptr), OfflineMsg); + } + if (strlen(Name) > 0) { + strcpy(V_name(volptr), Name); + } +#if TRANSARC_VOL_STATS /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. + * We don't overwrite the motd field, since it's now being used + * for stats */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); +#else + if (strlen(Motd) > 0) { + strcpy(V_motd(volptr), Motd); + } #endif /* FS_STATS_DETAILED */ + VUpdateVolume(&errorCode, volptr); + return(errorCode); - if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_RemoveFile; - - code = SAFSS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync); +} /*RXUpdate_VolumeStatus*/ -Bad_RemoveFile: - CallPostamble(tcon); -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (code == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } +/* old interface */ +static afs_int32 +Update_VolumeStatus(Volume *volptr, VolumeStatus *StoreVolStatus, + struct BBS *Name, struct BBS *OfflineMsg, + struct BBS *Motd) +{ + Error errorCode = 0; + if (StoreVolStatus->MinQuota > -1) + V_minquota(volptr) = StoreVolStatus->MinQuota; + if (StoreVolStatus->MaxQuota > -1) + V_maxquota(volptr) = StoreVolStatus->MaxQuota; + if (OfflineMsg->SeqLen > 1) + strcpy(V_offlineMessage(volptr), OfflineMsg->SeqBody); + if (Name->SeqLen > 1) + strcpy(V_name(volptr), Name->SeqBody); +#if TRANSARC_VOL_STATS + /* + * We don't overwrite the motd field, since it's now being used + * for stats + */ +#else + if (Motd->SeqLen > 1) + strcpy(V_motd(volptr), Motd->SeqBody); #endif /* FS_STATS_DETAILED */ + VUpdateVolume(&errorCode, volptr); + return(errorCode); - osi_auditU (acall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END); - return code; - -} /*SRXAFS_RemoveFile*/ +} /*Update_VolumeStatus*/ /* - * This routine is called exclusively from SRXAFS_CreateFile(), and should - * be merged in when possible. + * Get internal volume-related statistics from the Volume disk label + * structure and put it into the VolumeStatus structure, status; it's + * used by both SAFS_GetVolumeStatus and SAFS_SetVolumeStatus to return + * the volume status to the caller. */ static afs_int32 -SAFSS_CreateFile (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - struct AFSStoreStatus *InStatus, - struct AFSFid *OutFid, - struct AFSFetchStatus *OutFidStatus, - struct AFSFetchStatus *OutDirStatus, - struct AFSCallBack *CallBack, - struct AFSVolSync *Sync) +GetVolumeStatus(VolumeStatus *status, struct BBS *name, struct BBS *offMsg, + struct BBS *motd, Volume *volptr) { - Vnode * parentptr = 0; /* vnode of input Directory */ - Vnode * targetptr = 0; /* vnode of the new file */ - Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ - 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 */ - 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 */ - struct rx_connection *tcon = rx_ConnectionOf(acall); - - FidZero(&dir); - - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1, ("SAFS_CreateFile %s, Did = %u.%d.%d, Host %s, Id %d\n", - Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique, - inet_ntoa(logHostAddr), t_client->ViceId)); - FS_LOCK - AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++; - FS_UNLOCK - if (!FileNameOK(Name)) { - errorCode = EINVAL; - goto Bad_CreateFile; - } + status->Vid = V_id(volptr); + status->ParentId = V_parentId(volptr); + status->Online = V_inUse(volptr); + status->InService = V_inService(volptr); + status->Blessed = V_blessed(volptr); + status->NeedsSalvage = V_needsSalvaged(volptr); + if (VolumeWriteable(volptr)) + status->Type = ReadWrite; + else + status->Type = ReadOnly; + status->MinQuota = V_minquota(volptr); + status->MaxQuota = V_maxquota(volptr); + status->BlocksInUse = V_diskused(volptr); + status->PartBlocksAvail = volptr->partition->free; + status->PartMaxBlocks = volptr->partition->totalUsable; + strncpy(name->SeqBody, V_name(volptr), (int)name->MaxSeqLen); + name->SeqLen = strlen(V_name(volptr)) + 1; + if (name->SeqLen > name->MaxSeqLen) name->SeqLen = name -> MaxSeqLen; + strncpy(offMsg->SeqBody, V_offlineMessage(volptr), (int)name->MaxSeqLen); + offMsg->SeqLen = strlen(V_offlineMessage(volptr)) + 1; + if (offMsg->SeqLen > offMsg->MaxSeqLen) + offMsg->SeqLen = offMsg -> MaxSeqLen; +#ifdef notdef + /*Don't do anything with the motd field*/ + strncpy(motd->SeqBody, nullString, (int)offMsg->MaxSeqLen); + motd->SeqLen = strlen(nullString) + 1; +#endif + if (motd->SeqLen > motd->MaxSeqLen) + motd->SeqLen = motd -> MaxSeqLen; - /* - * Get associated volume/vnode for the parent dir; caller long are - * also returned - */ - if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, - MustBeDIR, &parentwhentargetnotdir, - &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_CreateFile; - } +} /*GetVolumeStatus*/ - /* set volume synchronization information */ - SetVolumeSync(Sync, volptr); +static afs_int32 +RXGetVolumeStatus(AFSFetchVolumeStatus *status, char **name, char **offMsg, + char **motd, Volume *volptr) +{ + int temp; - /* Can we write (and insert) onto the parent directory? */ - if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) { - goto Bad_CreateFile; - } - /* get a new vnode for the file to be created and set it up */ - if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr, - Name, OutFid, vFile, nBlocks(0)))) { - goto Bad_CreateFile; - } + status->Vid = V_id(volptr); + status->ParentId = V_parentId(volptr); + status->Online = V_inUse(volptr); + status->InService = V_inService(volptr); + status->Blessed = V_blessed(volptr); + status->NeedsSalvage = V_needsSalvaged(volptr); + if (VolumeWriteable(volptr)) + status->Type = ReadWrite; + else + status->Type = ReadOnly; + status->MinQuota = V_minquota(volptr); + status->MaxQuota = V_maxquota(volptr); + status->BlocksInUse = V_diskused(volptr); + status->PartBlocksAvail = volptr->partition->free; + status->PartMaxBlocks = volptr->partition->totalUsable; - /* update the status of the parent vnode */ -#if FS_STATS_DETAILED - Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, - parentptr->disk.linkCount, client->InSameNetwork); + /* now allocate and copy these things; they're freed by the RXGEN stub */ + temp = strlen(V_name(volptr)) + 1; + *name = malloc(temp); + strcpy(*name, V_name(volptr)); + temp = strlen(V_offlineMessage(volptr)) + 1; + *offMsg = malloc(temp); + strcpy(*offMsg, V_offlineMessage(volptr)); +#if TRANSARC_VOL_STATS + *motd = malloc(1); + strcpy(*motd, nullString); #else - Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, - parentptr->disk.linkCount); + temp = strlen(V_motd(volptr)) + 1; + *motd = malloc(temp); + strcpy(*motd, V_motd(volptr)); #endif /* FS_STATS_DETAILED */ - /* update the status of the new file's vnode */ - Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus, - parentptr, volptr, 0); +} /*RXGetVolumeStatus*/ - /* set up the return status for the parent dir and the newly created file */ - GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr); - GetStatus(parentptr, OutDirStatus, rights, anyrights, 0); - /* convert the write lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, parentptr); - assert(!errorCode || errorCode == VSALVAGE); - - /* break call back on parent dir */ - BreakCallBack(client->host, DirFid, 0); +static afs_int32 +FileNameOK(register char *aname) +{ + register afs_int32 i, tc; + i = strlen(aname); + if (i >= 4) { + /* watch for @sys on the right */ + if (strcmp(aname+i-4, "@sys") == 0) return 0; + } + while ((tc = *aname++)) { + if (tc == '/') return 0; /* very bad character to encounter */ + } + return 1; /* file name is ok */ - /* Return a callback promise for the newly created file to the caller */ - SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack); +} /*FileNameOK*/ -Bad_CreateFile: - /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); - FidZap(&dir); - ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode)); - return errorCode; -} /*SAFSS_CreateFile*/ +/* Debugging tool to print Volume Statu's contents */ +static void +PrintVolumeStatus(VolumeStatus *status) +{ + ViceLog(5,("Volume header contains:\n")); + ViceLog(5,("Vid = %u, Parent = %u, Online = %d, InService = %d, Blessed = %d, NeedsSalvage = %d\n", + status->Vid, status->ParentId, status->Online, status->InService, + status->Blessed, status->NeedsSalvage)); + ViceLog(5,("MinQuota = %d, MaxQuota = %d\n", status->MinQuota, status->MaxQuota)); + ViceLog(5,("Type = %d, BlocksInUse = %d, PartBlocksAvail = %d, PartMaxBlocks = %d\n", + status->Type, status->BlocksInUse, status->PartBlocksAvail, status->PartMaxBlocks)); + +} /*PrintVolumeStatus*/ -afs_int32 SRXAFS_CreateFile (struct rx_call *acall, +/* + * This variant of symlink is expressly to support the AFS/DFS translator + * and is not supported by the AFS fileserver. We just return EINVAL. + * The cache manager should not generate this call to an AFS cache manager. + */ +afs_int32 SRXAFS_DFSSymlink (struct rx_call *acall, struct AFSFid *DirFid, char *Name, + char *LinkContents, struct AFSStoreStatus *InStatus, struct AFSFid *OutFid, struct AFSFetchStatus *OutFidStatus, - struct AFSFetchStatus *OutDirStatus, - struct AFSCallBack *CallBack, + struct AFSFetchStatus *OutDirStatus, + struct AFSCallBack *CallBack, struct AFSVolSync *Sync) { - afs_int32 code; - struct rx_connection *tcon; -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ - - /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ - - if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_CreateFile; - - code = SAFSS_CreateFile (acall, DirFid, Name, InStatus, OutFid, - OutFidStatus, OutDirStatus, CallBack, Sync); - -Bad_CreateFile: - CallPostamble(tcon); - -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (code == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } -#endif /* FS_STATS_DETAILED */ + return EINVAL; +} - osi_auditU (acall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END); - return code; +afs_int32 SRXAFS_ResidencyCmd (struct rx_call *acall, struct AFSFid *Fid, + struct ResidencyCmdInputs *Inputs, + struct ResidencyCmdOutputs *Outputs) +{ + return EINVAL; +} -} /*SRXAFS_CreateFile*/ +#define AFSV_BUFFERSIZE 16384 +static struct afs_buffer { + struct afs_buffer *next; +} *freeBufferList = 0; +static int afs_buffersAlloced = 0; -/* - * This routine is called exclusively from SRXAFS_Rename(), and should be - * merged in when possible. - */ -static afs_int32 -SAFSS_Rename (struct rx_call *acall, - struct AFSFid *OldDirFid, - char *OldName, - struct AFSFid *NewDirFid, - char *NewName, - struct AFSFetchStatus *OutOldDirStatus, - struct AFSFetchStatus *OutNewDirStatus, - struct AFSVolSync *Sync) +static FreeSendBuffer(register struct afs_buffer *adata) { - Vnode * oldvptr = 0; /* vnode of the old Directory */ - Vnode * newvptr = 0; /* vnode of the new Directory */ - Vnode * fileptr = 0; /* vnode of the file to move */ - Vnode * newfileptr = 0; /* vnode of the file to delete */ - Vnode * testvptr = 0; /* used in directory tree walk */ - Vnode * parent = 0; /* parent for use in SetAccessList */ - int errorCode = 0; /* error code */ - int fileCode = 0; /* used when writing Vnodes */ - VnodeId testnode; /* used in directory tree walk */ - AFSFid fileFid; /* Fid of file to move */ - AFSFid newFileFid; /* Fid of new file */ - DirHandle olddir; /* Handle for dir package I/O */ - DirHandle newdir; /* Handle for dir package I/O */ - 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 */ - afs_int32 rights, anyrights; /* rights for this and any user */ - afs_int32 newrights; /* rights for this user */ - afs_int32 newanyrights; /* rights for any user */ - int doDelete; /* deleted the rename target (ref count now 0) */ - int code; - struct client *t_client; /* tmp ptr to client data */ - struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ - struct rx_connection *tcon = rx_ConnectionOf(acall); - - FidZero(&olddir); - FidZero(&newdir); - FidZero(&filedir); - FidZero(&newfiledir); - - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1, ("SAFS_Rename %s to %s, Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n", - OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode, - OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode, - NewDirFid->Unique, - inet_ntoa(logHostAddr), t_client->ViceId)); FS_LOCK - AFSCallStats.Rename++, AFSCallStats.TotalCalls++; + afs_buffersAlloced--; + adata->next = freeBufferList; + freeBufferList = adata; FS_UNLOCK - if (!FileNameOK(NewName)) { - errorCode = EINVAL; - goto Bad_Rename; - } - if (OldDirFid->Volume != NewDirFid->Volume) { - DFlush(); - errorCode = EXDEV; - goto Bad_Rename; - } - if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) || - (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) || - (strlen(NewName) == 0) || (strlen(OldName) == 0) ) { - DFlush(); - errorCode = EINVAL; - goto Bad_Rename; - } + return 0; - if (OldDirFid->Vnode <= NewDirFid->Vnode) { - if (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, - &oldvptr, MustBeDIR, &parent, - &client, WRITE_LOCK, &rights, - &anyrights)) { - DFlush(); - goto Bad_Rename; - } - if (OldDirFid->Vnode == NewDirFid->Vnode) { - newvptr = oldvptr; - newrights = rights, newanyrights = anyrights; - } - else - if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr, - &newvptr, MustBeDIR, &parent, - &client, WRITE_LOCK, &newrights, - &newanyrights))) { - DFlush(); - goto Bad_Rename; - } - } - else { - if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr, - &newvptr, MustBeDIR, &parent, - &client, WRITE_LOCK, &newrights, - &newanyrights))) { - DFlush(); - goto Bad_Rename; - } - if ((errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr, - MustBeDIR, &parent, &client, WRITE_LOCK, - &rights, &anyrights))) { - DFlush(); - goto Bad_Rename; - } - } +} /*FreeSendBuffer*/ - /* set volume synchronization information */ - SetVolumeSync(Sync, volptr); +/* allocate space for sender */ +static char *AllocSendBuffer() +{ + register struct afs_buffer *tp; - if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) { - goto Bad_Rename; - } - if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) { - goto Bad_Rename; + FS_LOCK + afs_buffersAlloced++; + if (!freeBufferList) { + FS_UNLOCK + return malloc(AFSV_BUFFERSIZE); } + tp = freeBufferList; + freeBufferList = tp->next; + FS_UNLOCK + return (char *) tp; - /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second - * call to CopyOnWrite returns error, it is not necessary to revert back - * the effects of the first call because the contents of the volume is - * not modified, it is only replicated. - */ - if (oldvptr->disk.cloned) - { - ViceLog(25, ("Rename : calling CopyOnWrite on old dir\n")); - if ( ( errorCode = CopyOnWrite(oldvptr, volptr) ) ) - goto Bad_Rename; - } - SetDirHandle(&olddir, oldvptr); - if (newvptr->disk.cloned) - { - ViceLog(25, ("Rename : calling CopyOnWrite on new dir\n")); - if ( ( errorCode = CopyOnWrite(newvptr, volptr) ) ) - goto Bad_Rename; - } +} /*AllocSendBuffer*/ + +/* + * This routine returns the status info associated with the targetptr vnode + * in the AFSFetchStatus structure. Some of the newer fields, such as + * SegSize and Group are not yet implemented + */ +static +void GetStatus(Vnode *targetptr, + AFSFetchStatus *status, + afs_int32 rights, + afs_int32 anyrights, + Vnode *parentptr) +{ + /* initialize return status from a vnode */ + status->InterfaceVersion = 1; + status->SyncCounter = status->dataVersionHigh = status->lockCount = + status->errorCode = 0; + status->ResidencyMask = 1; /* means for MR-AFS: file in /vicepr-partition */ + if (targetptr->disk.type == vFile) + status->FileType = File; + else if (targetptr->disk.type == vDirectory) + status->FileType = Directory; + else if (targetptr->disk.type == vSymlink) + status->FileType = SymbolicLink; + else + status->FileType = Invalid; /*invalid type field */ + status->LinkCount = targetptr->disk.linkCount; + status->Length_hi = 0; + status->Length = targetptr->disk.length; + status->DataVersion = targetptr->disk.dataVersion; + status->Author = targetptr->disk.author; + status->Owner = targetptr->disk.owner; + status->CallerAccess = rights; + status->AnonymousAccess = anyrights; + status->UnixModeBits = targetptr->disk.modeBits; + status->ClientModTime = targetptr->disk.unixModifyTime; /* This might need rework */ + status->ParentVnode = (status->FileType == Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber); + status->ParentUnique = (status->FileType == Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier); + status->ServerModTime = targetptr->disk.serverModifyTime; + status->Group = targetptr->disk.group; + status->lockCount = targetptr->disk.lock.lockCount; + status->errorCode = 0; - SetDirHandle(&newdir, newvptr); +} /*GetStatus*/ - /* Lookup the file to delete its vnode */ - if (Lookup(&olddir, OldName, &fileFid)) { - errorCode = ENOENT; - goto Bad_Rename; - } - if (fileFid.Vnode == oldvptr->vnodeNumber || - fileFid.Vnode == newvptr->vnodeNumber) { - errorCode = FSERR_ELOOP; - goto Bad_Rename; - } - fileFid.Volume = V_id(volptr); - fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK); - if (errorCode != 0) { - ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode)); - VTakeOffline (volptr); - goto Bad_Rename; - } - if (fileptr->disk.uniquifier != fileFid.Unique) { - ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName)); - VTakeOffline (volptr); - errorCode = EIO; - goto Bad_Rename; - } +static +afs_int32 common_FetchData64 (struct rx_call *acall, + struct AFSFid *Fid, + afs_int32 Pos, + afs_int32 Len, + struct AFSFetchStatus *OutStatus, + struct AFSCallBack *CallBack, + struct AFSVolSync *Sync, + int type) +{ + Vnode * targetptr = 0; /* pointer to vnode to fetch */ + Vnode * parentwhentargetnotdir = 0; /* parent vnode if vptr is a file */ + Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */ + 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 rx_connection *tcon; /* the connection we're part of */ + 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 */ +#if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval xferStartTime, + xferStopTime; /* Start/stop times for xfer portion*/ + struct timeval elapsedTime; /* Transfer time */ + afs_int32 bytesToXfer; /* # bytes to xfer*/ + afs_int32 bytesXferred; /* # bytes actually xferred*/ + int readIdx; /* Index of read stats array to bump*/ + static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */ - if (fileptr->disk.type != vDirectory && - oldvptr != newvptr && - fileptr->disk.linkCount != 1) { - /* - * Hard links exist to this file - cannot move one of the links to - * a new directory because of AFS restrictions (this is the same - * reason that links cannot be made across directories, i.e. - * access lists) - */ - errorCode = EXDEV; - goto Bad_Rename; - } + /* + * Set our stats pointers, remember when the RPC operation started, and + * tally the operation. + */ + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]); + xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ - /* Lookup the new file */ - if (!(Lookup(&newdir, NewName, &newFileFid))) { - if (readonlyServer) { - errorCode = VREADONLY; - goto Bad_Rename; - } - if (!(newrights & PRSFS_DELETE)) { - errorCode = EACCES; - goto Bad_Rename; - } - if (newFileFid.Vnode == oldvptr->vnodeNumber || - newFileFid.Vnode == newvptr->vnodeNumber || - newFileFid.Vnode == fileFid.Vnode) { - errorCode = EINVAL; - goto Bad_Rename; - } - newFileFid.Volume = V_id(volptr); - newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK); - if (errorCode != 0) { - ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode)); - VTakeOffline (volptr); - goto Bad_Rename; - } - if (fileptr->disk.uniquifier != fileFid.Unique) { - ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName)); - VTakeOffline (volptr); - errorCode = EIO; - goto Bad_Rename; - } - SetDirHandle(&newfiledir, newfileptr); - /* Now check that we're moving directories over directories properly, etc. - * return proper POSIX error codes: - * if fileptr is a file and new is a dir: EISDIR. - * if fileptr is a dir and new is a file: ENOTDIR. - * Also, dir to be removed must be empty, of course. - */ - if (newfileptr->disk.type == vDirectory) { - if (fileptr->disk.type != vDirectory) { - errorCode = EISDIR; - goto Bad_Rename; - } - if ((IsEmpty(&newfiledir))) { - errorCode = EEXIST; - goto Bad_Rename; - } - } - else { - if (fileptr->disk.type == vDirectory) { - errorCode = ENOTDIR; - goto Bad_Rename; - } - } - } + ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n", + Fid->Volume, Fid->Vnode, Fid->Unique)); + FS_LOCK + AFSCallStats.FetchData++, AFSCallStats.TotalCalls++; + FS_UNLOCK + + if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon)) + goto Bad_FetchData; + /* Get ptr to client data for user Id for logging */ + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); + ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n", + Fid->Volume, Fid->Vnode, Fid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); /* - * ok - now we check that the old name is not above new name in the - * directory structure. This is to prevent removing a subtree alltogether - */ - if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) { - for (testnode = newvptr->disk.parent; testnode != 0;) { - if (testnode == oldvptr->vnodeNumber) { - testnode = oldvptr->disk.parent; - continue; - } - if ((testnode == fileptr->vnodeNumber) || - (testnode == newvptr->vnodeNumber)) { - errorCode = FSERR_ELOOP; - goto Bad_Rename; - } - if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) { - errorCode = FSERR_ELOOP; - goto Bad_Rename; - } - testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK); - assert(errorCode == 0); - testnode = testvptr->disk.parent; - VPutVnode(&errorCode, testvptr); - assert(errorCode == 0); - } - } - /* Do the CopyonWrite first before modifying anything else. Copying is - * required because we may have to change entries for .. + * Get volume/vnode for the fetched file; caller's access rights to + * it are also returned */ - if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) ) - { - ViceLog(25, ("Rename : calling CopyOnWrite on target dir\n")); - if ( ( errorCode = CopyOnWrite(fileptr, volptr) ) ) - goto Bad_Rename; - } + if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, + DONTCHECK, &parentwhentargetnotdir, + &client, READ_LOCK, &rights, &anyrights))) + goto Bad_FetchData; - /* If the new name exists already, delete it and the file it points to */ - doDelete = 0; - if (newfileptr) { - /* Delete NewName from its directory */ - code = Delete(&newdir, NewName); - assert(code == 0); + SetVolumeSync(Sync, volptr); - /* Drop the link count */ - newfileptr->disk.linkCount--; - if (newfileptr->disk.linkCount == 0) { /* Link count 0 - delete */ - VAdjustDiskUsage(&errorCode, volptr, - -(int)nBlocks(newfileptr->disk.length), 0); - if (VN_GET_INO(newfileptr)) { - IH_REALLYCLOSE(newfileptr->handle); - errorCode = IH_DEC(V_linkHandle(volptr), - VN_GET_INO(newfileptr), - V_parentId(volptr)); - IH_RELEASE(newfileptr->handle); - if (errorCode == -1) { - ViceLog(0, ("Del: inode=%s, name=%s, errno=%d\n", - PrintInode(NULL, VN_GET_INO(newfileptr)), - NewName, errno)); - if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO)) - ViceLog(0, ("Do we need to fsck?")); - } - } - VN_SET_INO(newfileptr, (Inode)0); - newfileptr->delete = 1; /* Mark NewName vnode to delete */ - doDelete = 1; - } else { - /* Link count did not drop to zero. - * Mark NewName vnode as changed - updates stime. - */ - newfileptr->changed_newTime = 1; - } +#if FS_STATS_DETAILED + /* + * Remember that another read operation was performed. + */ + FS_LOCK + if (client->InSameNetwork) + readIdx = VOL_STATS_SAME_NET; + else + readIdx = VOL_STATS_DIFF_NET; + V_stat_reads(volptr, readIdx)++; + if (client->ViceId != AnonymousID) { + V_stat_reads(volptr, readIdx+1)++; } - + FS_UNLOCK +#endif /* FS_STATS_DETAILED */ + + /* Check whether the caller has permission access to fetch the data */ + if ((errorCode = Check_PermissionRights(targetptr, client, rights, + CHK_FETCHDATA, 0))) + goto Bad_FetchData; + /* - * If the create below fails, and the delete above worked, we have - * removed the new name and not replaced it. This is not very likely, - * but possible. We could try to put the old file back, but it is - * highly unlikely that it would work since it would involve issuing - * another create. + * Drop the read lock on the parent directory after saving the parent + * vnode information we need to pass to GetStatus */ - if ((errorCode = Create(&newdir,(char *) NewName, &fileFid))) - goto Bad_Rename; + if (parentwhentargetnotdir != NULL) { + tparentwhentargetnotdir = *parentwhentargetnotdir; + VPutVnode(&fileCode, parentwhentargetnotdir); + assert(!fileCode || (fileCode == VSALVAGE)); + parentwhentargetnotdir = NULL; + } - /* Delete the old name */ - assert(Delete(&olddir,(char *) OldName) == 0); +#if FS_STATS_DETAILED + /* + * Remember when the data transfer started. + */ + TM_GetTimeOfDay(&xferStartTime, 0); +#endif /* FS_STATS_DETAILED */ - /* if the directory length changes, reflect it in the statistics */ + /* actually do the data transfer */ #if FS_STATS_DETAILED - Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId, - oldvptr->disk.linkCount, client->InSameNetwork); - Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId, - newvptr->disk.linkCount, client->InSameNetwork); + errorCode = FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type, + &bytesToXfer, &bytesXferred); #else - Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId, - oldvptr->disk.linkCount); - Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId, - newvptr->disk.linkCount); + if ((errorCode = FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type))) + goto Bad_FetchData; #endif /* FS_STATS_DETAILED */ - if (oldvptr == newvptr) - oldvptr->disk.dataVersion--; /* Since it was bumped by 2! */ +#if FS_STATS_DETAILED + /* + * At this point, the data transfer is done, for good or ill. Remember + * when the transfer ended, bump the number of successes/failures, and + * integrate the transfer size and elapsed time into the stats. If the + * operation failed, we jump to the appropriate point. + */ + TM_GetTimeOfDay(&xferStopTime, 0); + FS_LOCK + (xferP->numXfers)++; + if (!errorCode) { + (xferP->numSuccesses)++; - fileptr->disk.parent = newvptr->vnodeNumber; - fileptr->changed_newTime = 1; /* status change of moved file */ + /* + * Bump the xfer sum by the number of bytes actually sent, NOT the + * target number. + */ + tot_bytesXferred += bytesXferred; + (xferP->sumBytes) += (tot_bytesXferred >> 10); + tot_bytesXferred &= 0x3FF; + if (bytesXferred < xferP->minBytes) + xferP->minBytes = bytesXferred; + if (bytesXferred > xferP->maxBytes) + xferP->maxBytes = bytesXferred; - /* if we are dealing with a rename of a directory */ - if (fileptr->disk.type == vDirectory) { - assert(!fileptr->disk.cloned); - SetDirHandle(&filedir, fileptr); - /* fix .. to point to the correct place */ - Delete(&filedir, ".."); /* No assert--some directories may be bad */ - assert(Create(&filedir, "..", NewDirFid) == 0); - fileptr->disk.dataVersion++; - /* if the parent directories are different the link counts have to be */ - /* changed due to .. in the renamed directory */ - if (oldvptr != newvptr) { - oldvptr->disk.linkCount--; - newvptr->disk.linkCount++; - } - } + /* + * Tally the size of the object. Note: we tally the actual size, + * NOT the number of bytes that made it out over the wire. + */ + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0) + (xferP->count[0])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1) + (xferP->count[1])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2) + (xferP->count[2])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3) + (xferP->count[3])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4) + (xferP->count[4])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5) + (xferP->count[5])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6) + (xferP->count[6])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7) + (xferP->count[7])++; + else + (xferP->count[8])++; - /* set up return status */ - GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, 0); - GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, 0); - if (newfileptr && doDelete) { - DeleteFileCallBacks(&newFileFid); /* no other references */ - } + fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime); + fs_stats_AddTo((xferP->sumTime), elapsedTime); + fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) { + fs_stats_TimeAssign((xferP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) { + fs_stats_TimeAssign((xferP->maxTime), elapsedTime); + } + } + FS_UNLOCK + /* + * Finally, go off to tell our caller the bad news in case the + * fetch failed. + */ + if (errorCode) + goto Bad_FetchData; +#endif /* FS_STATS_DETAILED */ - DFlush(); + /* write back the OutStatus from the target vnode */ + GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir); - /* convert the write locks to a read locks before breaking callbacks */ - VVnodeWriteToRead(&errorCode, newvptr); - assert(!errorCode || errorCode == VSALVAGE); - if (oldvptr != newvptr) { - VVnodeWriteToRead(&errorCode, oldvptr); - assert(!errorCode || errorCode == VSALVAGE); - } - if (newfileptr && !doDelete) { - /* convert the write lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, newfileptr); - assert(!errorCode || errorCode == VSALVAGE); - } + /* if a r/w volume, promise a callback to the caller */ + if (VolumeWriteable(volptr)) + SetCallBackStruct(AddCallBack(client->host, Fid), CallBack); + else { + struct AFSFid myFid; + memset(&myFid, 0, sizeof(struct AFSFid)); + myFid.Volume = Fid->Volume; + SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack); + } - /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid */ - BreakCallBack(client->host, NewDirFid, 0); - if (oldvptr != newvptr) { - BreakCallBack(client->host, OldDirFid, 0); - if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */ - BreakCallBack(client->host, &fileFid, 0); - } - if (newfileptr) { - /* Note: it is not necessary to break the callback */ - if (doDelete) - DeleteFileCallBacks(&newFileFid); /* no other references */ - else - /* other's still exist (with wrong link count) */ - BreakCallBack(client->host, &newFileFid, 1); - } +Bad_FetchData: + /* Update and store volume/vnode and parent vnodes back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode)); + CallPostamble(tcon); -Bad_Rename: - if (newfileptr) { - VPutVnode(&fileCode, newfileptr); - assert(fileCode == 0); - } - PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0), - oldvptr, volptr); - FidZap(&olddir); - FidZap(&newdir); - FidZap(&filedir); - FidZap(&newfiledir); - ViceLog(2, ("SAFS_Rename returns %d\n", errorCode)); - return errorCode; +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (errorCode == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK + } -} /*SAFSS_Rename*/ +#endif /* FS_STATS_DETAILED */ + + osi_auditU (acall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END); + return(errorCode); + +} /*SRXAFS_FetchData*/ + +afs_int32 SRXAFS_FetchData (struct rx_call *acall, + struct AFSFid *Fid, + afs_int32 Pos, + afs_int32 Len, + struct AFSFetchStatus *OutStatus, + struct AFSCallBack *CallBack, + struct AFSVolSync *Sync) + +{ + int code; + + code = common_FetchData64 (acall, Fid, Pos, Len, OutStatus, + CallBack, Sync, 0); + return code; +} + +afs_int32 SRXAFS_FetchData64 (struct rx_call *acall, + struct AFSFid *Fid, + afs_int64 Pos, + afs_int64 Len, + struct AFSFetchStatus *OutStatus, + struct AFSCallBack *CallBack, + struct AFSVolSync *Sync) +{ + int code; + afs_int32 tPos, tLen; + +#ifdef AFS_64BIT_ENV + if (Pos + Len > 0x7fffffff) + return E2BIG; + tPos = Pos; + tLen = Len; +#else /* AFS_64BIT_ENV */ + if (Pos.high || Len.high) + return E2BIG; + tPos = Pos.low; + tLen = Len.low; +#endif /* AFS_64BIT_ENV */ + code = common_FetchData64 (acall, Fid, tPos, tLen, OutStatus, + CallBack, Sync, 1); + return code; +} -afs_int32 SRXAFS_Rename (struct rx_call *acall, - struct AFSFid *OldDirFid, - char *OldName, - struct AFSFid *NewDirFid, - char *NewName, - struct AFSFetchStatus *OutOldDirStatus, - struct AFSFetchStatus *OutNewDirStatus, - struct AFSVolSync *Sync) +afs_int32 SRXAFS_FetchACL (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSOpaque *AccessList, + struct AFSFetchStatus *OutStatus, + struct AFSVolSync *Sync) { - afs_int32 code; - struct rx_connection *tcon; + Vnode * targetptr = 0; /* pointer to vnode to fetch */ + 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 */ + afs_int32 rights, anyrights; /* rights for this and any user */ + struct rx_connection *tcon = rx_ConnectionOf(acall); + struct client *t_client; /* tmp ptr to client data */ + struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ #if FS_STATS_DETAILED struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ struct timeval opStartTime, @@ -2533,195 +2260,176 @@ afs_int32 SRXAFS_Rename (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]); FS_LOCK (opP->numOps)++; FS_UNLOCK TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ - if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_Rename; + ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n", + Fid->Volume, Fid->Vnode, Fid->Unique)); + FS_LOCK + AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++; + FS_UNLOCK + if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_FetchACL; - code = SAFSS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName, - OutOldDirStatus, OutNewDirStatus, Sync); + /* Get ptr to client data for user Id for logging */ + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); + ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n", + Fid->Volume, Fid->Vnode, Fid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); -Bad_Rename: + AccessList->AFSOpaque_len = 0; + AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX); + + /* + * Get volume/vnode for the fetched file; caller's access rights to it + * are also returned + */ + if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, + DONTCHECK, &parentwhentargetnotdir, + &client, READ_LOCK, &rights, &anyrights))) + goto Bad_FetchACL; + + SetVolumeSync(Sync, volptr); + + /* Check whether we have permission to fetch the ACL */ + if ((errorCode = Check_PermissionRights(targetptr, client, rights, + CHK_FETCHACL, 0))) + goto Bad_FetchACL; + + /* Get the Access List from the dir's vnode */ + if ((errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir, + AccessList))) + goto Bad_FetchACL; + + /* Get OutStatus back From the target Vnode */ + GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir); + +Bad_FetchACL: + /* Update and store volume/vnode and parent vnodes back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n", + errorCode, AccessList->AFSOpaque_val)); CallPostamble(tcon); #if FS_STATS_DETAILED TM_GetTimeOfDay(&opStopTime, 0); - if (code == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); + if (errorCode == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK } - FS_UNLOCK - } #endif /* FS_STATS_DETAILED */ - osi_auditU (acall, RenameFileEvent, code, AUD_FID, OldDirFid, AUD_STR, OldName, AUD_FID, NewDirFid, AUD_STR, NewName, AUD_END); - return code; - -} /*SRXAFS_Rename*/ + osi_auditU (acall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END); + return errorCode; +} /*SRXAFS_FetchACL*/ /* - * This routine is called exclusively by SRXAFS_Symlink(), and should be + * This routine is called exclusively by SRXAFS_FetchStatus(), and should be * merged into it when possible. */ -static afs_int32 -SAFSS_Symlink (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - char *LinkContents, - struct AFSStoreStatus *InStatus, - struct AFSFid *OutFid, - struct AFSFetchStatus *OutFidStatus, - struct AFSFetchStatus *OutDirStatus, - struct AFSVolSync *Sync) - +static +afs_int32 SAFSS_FetchStatus (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSFetchStatus *OutStatus, + struct AFSCallBack *CallBack, + struct AFSVolSync *Sync) { - Vnode * parentptr = 0; /* vnode of input Directory */ - Vnode * targetptr = 0; /* vnode of the new link */ - Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ - int errorCode = 0; /* error code */ - int 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 */ - afs_int32 rights, anyrights, fd; /* rights for this and any user */ + Vnode * targetptr = 0; /* pointer to vnode to fetch */ + 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 */ + 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 */ - FdHandle_t *fdP; struct rx_connection *tcon = rx_ConnectionOf(acall); - FidZero(&dir); - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1, ("SAFS_Symlink %s to %s, Did = %u.%d.%d, Host %s, Id %d\n", Name, - LinkContents, DirFid->Volume, DirFid->Vnode, DirFid->Unique, + ViceLog(1, ("SAFS_FetchStatus, Fid = %u.%d.%d, Host %s, Id %d\n", + Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr), t_client->ViceId)); FS_LOCK - AFSCallStats.Symlink++, AFSCallStats.TotalCalls++; + AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++; FS_UNLOCK - if (!FileNameOK(Name)) { - errorCode = EINVAL; - goto Bad_SymLink; - } - /* - * Get the vnode and volume for the parent dir along with the caller's - * rights to it + * Get volume/vnode for the fetched file; caller's rights to it are + * also returned */ - if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, - MustBeDIR, &parentwhentargetnotdir, - &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_SymLink; - } + if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, + DONTCHECK, &parentwhentargetnotdir, + &client, READ_LOCK, &rights, &anyrights))) + goto Bad_FetchStatus; /* set volume synchronization information */ SetVolumeSync(Sync, volptr); - /* Does the caller has insert (and write) access to the parent directory? */ - if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) { - goto Bad_SymLink; - } - - /* - * If we're creating a mount point (any x bits clear), we must have - * administer access to the directory, too. Always allow sysadmins - * to do this. - */ - if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) { - if (readonlyServer) { - errorCode = VREADONLY; - goto Bad_SymLink; - } - /* - * We have a mountpoint, 'cause we're trying to set the Unix mode - * bits to something with some x bits missing (default mode bits - * if AFS_SETMODE is false is 0777) - */ - if (VanillaUser(client) && !(rights & PRSFS_ADMINISTER)) { - errorCode = EACCES; - goto Bad_SymLink; - } - } - - /* get a new vnode for the symlink and set it up */ - if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr, - Name, OutFid, vSymlink, - nBlocks(strlen((char *) LinkContents))))) { - goto Bad_SymLink; + /* Are we allowed to fetch Fid's status? */ + if (targetptr->disk.type != vDirectory) { + if ((errorCode = Check_PermissionRights(targetptr, client, rights, + CHK_FETCHSTATUS, 0))) { + if (rx_GetCallAbortCode(acall) == errorCode) + rx_SetCallAbortCode(acall, 0); + goto Bad_FetchStatus; + } } - /* update the status of the parent vnode */ -#if FS_STATS_DETAILED - Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, - parentptr->disk.linkCount, client->InSameNetwork); -#else - Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, - parentptr->disk.linkCount); -#endif /* FS_STATS_DETAILED */ - - /* update the status of the new symbolic link file vnode */ - Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus, parentptr, - volptr, strlen((char *)LinkContents)); - - /* Write the contents of the symbolic link name into the target inode */ - fdP = IH_OPEN(targetptr->handle); - assert(fdP != NULL); - assert(FDH_WRITE(fdP, (char *) LinkContents, strlen((char *) LinkContents)) == strlen((char *) LinkContents)); - FDH_CLOSE(fdP); - /* - * Set up and return modified status for the parent dir and new symlink - * to caller. - */ - GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr); - GetStatus(parentptr, OutDirStatus, rights, anyrights, 0); - - /* convert the write lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, parentptr); - assert(!errorCode || errorCode == VSALVAGE); - - /* break call back on the parent dir */ - BreakCallBack(client->host, DirFid, 0); + /* set OutStatus From the Fid */ + GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir); -Bad_SymLink: - /* Write the all modified vnodes (parent, new files) and volume back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); - FidZap(&dir); - ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode)); - return errorCode; + /* If a r/w volume, also set the CallBack state */ + if (VolumeWriteable(volptr)) + SetCallBackStruct(AddCallBack(client->host, Fid), CallBack); + else { + struct AFSFid myFid; + memset(&myFid, 0, sizeof(struct AFSFid)); + myFid.Volume = Fid->Volume; + SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack); + } -} /*SAFSS_Symlink*/ +Bad_FetchStatus: + /* Update and store volume/vnode and parent vnodes back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode)); + return errorCode; +} /*SAFSS_FetchStatus*/ -afs_int32 SRXAFS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync) - struct AFSVolSync *Sync; - struct rx_call *acall; /* Rx call */ - struct AFSFid *DirFid; /* Parent dir's fid */ - char *Name; /* File name to create */ - char *LinkContents; /* Contents of the new created file */ - struct AFSStoreStatus *InStatus; /* Input status for the new symbolic link */ - struct AFSFid *OutFid; /* Fid for newly created symbolic link */ - struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */ - struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */ +afs_int32 SRXAFS_BulkStatus(struct rx_call *acall, + struct AFSCBFids *Fids, + struct AFSBulkStats *OutStats, + struct AFSCBs *CallBacks, + struct AFSVolSync *Sync) { - afs_int32 code; - struct rx_connection *tcon; + register int i; + afs_int32 nfiles; + Vnode * targetptr = 0; /* pointer to vnode to fetch */ + 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 */ + 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); #if FS_STATS_DETAILED struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ struct timeval opStartTime, @@ -2732,192 +2440,268 @@ afs_int32 SRXAFS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, O * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]); FS_LOCK (opP->numOps)++; FS_UNLOCK TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ - if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_Symlink; + ViceLog(1, ("SAFS_BulkStatus\n")); + FS_LOCK + AFSCallStats.TotalCalls++; + FS_UNLOCK - code = SAFSS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, - OutFidStatus, OutDirStatus, Sync); + nfiles = Fids->AFSCBFids_len; /* # of files in here */ + if (nfiles <= 0) { /* Sanity check */ + errorCode = EINVAL; + goto Audit_and_Return; + } -Bad_Symlink: + /* allocate space for return output parameters */ + OutStats->AFSBulkStats_val = (struct AFSFetchStatus *) + malloc(nfiles * sizeof(struct AFSFetchStatus)); + OutStats->AFSBulkStats_len = nfiles; + CallBacks->AFSCBs_val = (struct AFSCallBack *) + malloc(nfiles * sizeof(struct AFSCallBack)); + CallBacks->AFSCBs_len = nfiles; + + if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_BulkStatus; + + tfid = Fids->AFSCBFids_val; + for (i=0; idisk.type != vDirectory) { + if ((errorCode = Check_PermissionRights(targetptr, client, rights, + CHK_FETCHSTATUS, 0))) { + if (rx_GetCallAbortCode(acall) == errorCode) + rx_SetCallAbortCode(acall, 0); + goto Bad_BulkStatus; + } + } + + /* set OutStatus From the Fid */ + GetStatus(targetptr, &OutStats->AFSBulkStats_val[i], + rights, anyrights, parentwhentargetnotdir); + + /* If a r/w volume, also set the CallBack state */ + if (VolumeWriteable(volptr)) + SetCallBackStruct(AddBulkCallBack(client->host, tfid), + &CallBacks->AFSCBs_val[i]); + else { + struct AFSFid myFid; + memset(&myFid, 0, sizeof(struct AFSFid)); + myFid.Volume = tfid->Volume; + SetCallBackStruct(AddVolCallBack(client->host, &myFid), + &CallBacks->AFSCBs_val[i]); + } + + /* put back the file ID and volume */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr); + parentwhentargetnotdir = (Vnode *) 0; + targetptr = (Vnode *) 0; + volptr = (Volume *) 0; + } + +Bad_BulkStatus: + /* Update and store volume/vnode and parent vnodes back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); CallPostamble(tcon); #if FS_STATS_DETAILED TM_GetTimeOfDay(&opStopTime, 0); - if (code == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } + if (errorCode == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK + } #endif /* FS_STATS_DETAILED */ - osi_auditU (acall, SymlinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END); - return code; +Audit_and_Return: + ViceLog(2, ("SAFS_BulkStatus returns %d\n", errorCode)); + osi_auditU (acall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END); + return errorCode; -} /*SRXAFS_Symlink*/ +} /*SRXAFS_BulkStatus*/ -/* - * This routine is called exclusively by SRXAFS_Link(), and should be - * merged into it when possible. - */ -static afs_int32 -SAFSS_Link (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - struct AFSFid *ExistingFid, - struct AFSFetchStatus *OutFidStatus, - struct AFSFetchStatus *OutDirStatus, - struct AFSVolSync *Sync) +afs_int32 SRXAFS_InlineBulkStatus(struct rx_call *acall, + struct AFSCBFids *Fids, + struct AFSBulkStats *OutStats, + struct AFSCBs *CallBacks, + struct AFSVolSync *Sync) { - Vnode * parentptr = 0; /* vnode of input Directory */ - Vnode * targetptr = 0; /* vnode of the new file */ - Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ - 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 */ + register int i; + afs_int32 nfiles; + Vnode * targetptr = 0; /* pointer to vnode to fetch */ + 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 */ 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 */ - struct rx_connection *tcon = rx_ConnectionOf(acall); + register struct AFSFid *tfid; /* file id we're dealing with now */ + struct rx_connection *tcon; + AFSFetchStatus *tstatus; +#if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ - FidZero(&dir); + /* + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. + */ + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ - /* Get ptr to client data for user Id for logging */ - t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1, ("SAFS_Link %s, Did = %u.%d.%d, Fid = %u.%d.%d, Host %s, Id %d\n", - Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique, - ExistingFid->Volume, ExistingFid->Vnode, ExistingFid->Unique, - inet_ntoa(logHostAddr), t_client->ViceId)); + ViceLog(1, ("SAFS_InlineBulkStatus\n")); FS_LOCK - AFSCallStats.Link++, AFSCallStats.TotalCalls++; + AFSCallStats.TotalCalls++; FS_UNLOCK - if (DirFid->Volume != ExistingFid->Volume) { - errorCode = EXDEV; - goto Bad_Link; - } - if (!FileNameOK(Name)) { + + nfiles = Fids->AFSCBFids_len; /* # of files in here */ + if (nfiles <= 0) { /* Sanity check */ errorCode = EINVAL; - goto Bad_Link; + goto Audit_and_Return; } - /* - * Get the vnode and volume for the parent dir along with the caller's - * rights to it - */ - if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, - MustBeDIR, &parentwhentargetnotdir, - &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_Link; + /* allocate space for return output parameters */ + OutStats->AFSBulkStats_val = (struct AFSFetchStatus *) + malloc(nfiles * sizeof(struct AFSFetchStatus)); + OutStats->AFSBulkStats_len = nfiles; + CallBacks->AFSCBs_val = (struct AFSCallBack *) + malloc(nfiles * sizeof(struct AFSCallBack)); + CallBacks->AFSCBs_len = nfiles; + + if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) { + goto Bad_InlineBulkStatus; } - /* set volume synchronization information */ - SetVolumeSync(Sync, volptr); + tfid = Fids->AFSCBFids_val; + for (i=0; iAFSBulkStats_val[i]; + tstatus->errorCode = errorCode; + parentwhentargetnotdir = (Vnode *) 0; + targetptr = (Vnode *) 0; + volptr = (Volume *) 0; + continue; + } + + /* set volume synchronization information, but only once per call */ + if (i == nfiles) + SetVolumeSync(Sync, volptr); - /* Can the caller insert into the parent directory? */ - if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) { - goto Bad_Link; - } + /* Are we allowed to fetch Fid's status? */ + if (targetptr->disk.type != vDirectory) { + if ((errorCode = Check_PermissionRights(targetptr, client, rights, + CHK_FETCHSTATUS, 0))) { + tstatus = &OutStats->AFSBulkStats_val[i]; + tstatus->errorCode = errorCode; + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr); + parentwhentargetnotdir = (Vnode *) 0; + targetptr = (Vnode *) 0; + volptr = (Volume *) 0; + continue; + } + } - if (((DirFid->Vnode & 1) && (ExistingFid->Vnode & 1)) || - (DirFid->Vnode == ExistingFid->Vnode)) { /* at present, */ - /* AFS fileservers always have directory vnodes that are odd. */ - errorCode = EISDIR; - goto Bad_Link; - } + /* set OutStatus From the Fid */ + GetStatus(targetptr, (struct AFSFetchStatus *) &OutStats->AFSBulkStats_val[i], + rights, anyrights, parentwhentargetnotdir); - /* get the file vnode */ - if ((errorCode = CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK))) { - goto Bad_Link; - } - if (targetptr->disk.type != vFile) { - errorCode = EISDIR; - goto Bad_Link; - } - if (targetptr->disk.parent != DirFid->Vnode) { - errorCode = EXDEV; - goto Bad_Link; - } - if (parentptr->disk.cloned) - { - ViceLog(25, ("Link : calling CopyOnWrite on target dir\n")); - if ( ( errorCode = CopyOnWrite(parentptr, volptr))) - goto Bad_Link; /* disk full error */ + /* If a r/w volume, also set the CallBack state */ + if (VolumeWriteable(volptr)) + SetCallBackStruct(AddBulkCallBack(client->host, tfid), + &CallBacks->AFSCBs_val[i]); + else { + struct AFSFid myFid; + memset(&myFid, 0, sizeof(struct AFSFid)); + myFid.Volume = tfid->Volume; + SetCallBackStruct(AddVolCallBack(client->host, &myFid), + &CallBacks->AFSCBs_val[i]); + } + + /* put back the file ID and volume */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr); + parentwhentargetnotdir = (Vnode *) 0; + targetptr = (Vnode *) 0; + volptr = (Volume *) 0; } - /* add the name to the directory */ - SetDirHandle(&dir, parentptr); - if ((errorCode = Create(&dir, (char *)Name, ExistingFid))) - goto Bad_Link; - DFlush(); +Bad_InlineBulkStatus: + /* Update and store volume/vnode and parent vnodes back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + CallPostamble(tcon); - /* update the status in the parent vnode */ - /**WARNING** --> disk.author SHOULDN'T be modified???? */ #if FS_STATS_DETAILED - Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, - parentptr->disk.linkCount, client->InSameNetwork); -#else - Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, - parentptr->disk.linkCount); -#endif /* FS_STATS_DETAILED */ - - targetptr->disk.linkCount++; - targetptr->disk.author = client->ViceId; - targetptr->changed_newTime = 1; /* Status change of linked-to file */ - - /* set up return status */ - GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr); - GetStatus(parentptr, OutDirStatus, rights, anyrights, 0); + TM_GetTimeOfDay(&opStopTime, 0); + if (errorCode == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK + } - /* convert the write locks to read locks before breaking callbacks */ - VVnodeWriteToRead(&errorCode, targetptr); - assert(!errorCode || errorCode == VSALVAGE); - VVnodeWriteToRead(&errorCode, parentptr); - assert(!errorCode || errorCode == VSALVAGE); - - /* break call back on DirFid */ - BreakCallBack(client->host, DirFid, 0); - /* - * We also need to break the callback for the file that is hard-linked since part - * of its status (like linkcount) is changed - */ - BreakCallBack(client->host, ExistingFid, 0); +#endif /* FS_STATS_DETAILED */ -Bad_Link: - /* Write the all modified vnodes (parent, new files) and volume back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); - FidZap(&dir); - ViceLog(2, ("SAFS_Link returns %d\n", errorCode)); - return errorCode; +Audit_and_Return: + ViceLog(2, ("SAFS_InlineBulkStatus returns %d\n", errorCode)); + osi_auditU (acall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END); + return 0; -} /*SAFSS_Link*/ +} /*SRXAFS_InlineBulkStatus*/ -afs_int32 SRXAFS_Link (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - struct AFSFid *ExistingFid, - struct AFSFetchStatus *OutFidStatus, - struct AFSFetchStatus *OutDirStatus, - struct AFSVolSync *Sync) +afs_int32 SRXAFS_FetchStatus (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSFetchStatus *OutStatus, + struct AFSCallBack *CallBack, + struct AFSVolSync *Sync) { afs_int32 code; struct rx_connection *tcon; @@ -2931,7 +2715,7 @@ afs_int32 SRXAFS_Link (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]); FS_LOCK (opP->numOps)++; FS_UNLOCK @@ -2939,186 +2723,318 @@ afs_int32 SRXAFS_Link (struct rx_call *acall, #endif /* FS_STATS_DETAILED */ if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_Link; + goto Bad_FetchStatus; - code = SAFSS_Link (acall, DirFid, Name, ExistingFid, OutFidStatus, - OutDirStatus, Sync); - -Bad_Link: + code = SAFSS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync); + +Bad_FetchStatus: CallPostamble(tcon); #if FS_STATS_DETAILED TM_GetTimeOfDay(&opStopTime, 0); if (code == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK } - FS_UNLOCK - } #endif /* FS_STATS_DETAILED */ - osi_auditU (acall, LinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_FID, ExistingFid, AUD_END); + osi_auditU (acall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END); return code; -} /*SRXAFS_Link*/ - +} /*SRXAFS_FetchStatus*/ -/* - * This routine is called exclusively by SRXAFS_MakeDir(), and should be - * merged into it when possible. - */ -static afs_int32 -SAFSS_MakeDir (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - struct AFSStoreStatus *InStatus, - struct AFSFid *OutFid, - struct AFSFetchStatus *OutFidStatus, - struct AFSFetchStatus *OutDirStatus, - struct AFSCallBack *CallBack, - struct AFSVolSync *Sync) +afs_int32 SRXAFS_StoreData (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSStoreStatus *InStatus, + afs_uint32 Pos, + afs_uint32 Length, + afs_uint32 FileLength, + struct AFSFetchStatus *OutStatus, + struct AFSVolSync *Sync) { - Vnode * parentptr = 0; /* vnode of input Directory */ - Vnode * targetptr = 0; /* vnode of the new file */ - Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ + Vnode * targetptr = 0; /* pointer to input fid */ + Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */ + Vnode tparentwhentargetnotdir; /* parent vnode for GetStatus */ + int errorCode = 0; /* return code for caller */ + int fileCode = 0; /* return code from vol package */ Volume * volptr = 0; /* pointer to the volume header */ - int errorCode = 0; /* error code */ - struct acl_accessList * newACL; /* Access list */ - 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 */ 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 */ - struct rx_connection *tcon = rx_ConnectionOf(acall); + struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ + struct rx_connection *tcon; +#if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval xferStartTime, + xferStopTime; /* Start/stop times for xfer portion*/ + struct timeval elapsedTime; /* Transfer time */ + afs_int32 bytesToXfer; /* # bytes to xfer */ + afs_int32 bytesXferred; /* # bytes actually xfer */ + static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */ + + /* + * Set our stats pointers, remember when the RPC operation started, and + * tally the operation. + */ + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]); + xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + + ViceLog(1, ("StoreData: Fid = %u.%d.%d\n", + Fid->Volume, Fid->Vnode, Fid->Unique)); + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ + + FS_LOCK + AFSCallStats.StoreData++, AFSCallStats.TotalCalls++; + FS_UNLOCK - FidZero(&dir); - FidZero(&parentdir); + if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_StoreData; /* Get ptr to client data for user Id for logging */ t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1, ("SAFS_MakeDir %s, Did = %u.%d.%d, Host %s, Id %d\n", - Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique, + ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n", + Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr), t_client->ViceId)); - FS_LOCK - AFSCallStats.MakeDir++, AFSCallStats.TotalCalls++; - FS_UNLOCK - if (!FileNameOK(Name)) { - errorCode = EINVAL; - goto Bad_MakeDir; - } /* - * Get the vnode and volume for the parent dir along with the caller's - * rights to it. + * Get associated volume/vnode for the stored file; caller's rights + * are also returned */ - if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, - MustBeDIR, &parentwhentargetnotdir, + if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, + MustNOTBeDIR, &parentwhentargetnotdir, &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_MakeDir; + goto Bad_StoreData; } - + /* set volume synchronization information */ SetVolumeSync(Sync, volptr); - /* Write access to the parent directory? */ -#ifdef DIRCREATE_NEED_WRITE + if ((targetptr->disk.type == vSymlink)) { + /* Should we return a better error code here??? */ + errorCode = EISDIR; + goto Bad_StoreData; + } + + /* Check if we're allowed to store the data */ + if ((errorCode = Check_PermissionRights(targetptr, client, rights, + CHK_STOREDATA, InStatus))) { + goto Bad_StoreData; + } + /* - * requires w access for the user to create a directory. this - * closes a loophole in the current security arrangement, since a - * user with i access only can create a directory and get the - * implcit a access that goes with dir ownership, and proceed to - * subvert quota in the volume. + * Drop the read lock on the parent directory after saving the parent + * vnode information we need to pass to GetStatus */ - if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) || - (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) { -#else - if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) { -#endif /* DIRCREATE_NEED_WRITE */ - goto Bad_MakeDir; + if (parentwhentargetnotdir != NULL) { + tparentwhentargetnotdir = *parentwhentargetnotdir; + VPutVnode(&fileCode, parentwhentargetnotdir); + assert(!fileCode || (fileCode == VSALVAGE)); + parentwhentargetnotdir = NULL; } -#define EMPTYDIRBLOCKS 2 - /* get a new vnode and set it up */ - if ((errorCode = Alloc_NewVnode(parentptr, &parentdir, volptr, &targetptr, - Name, OutFid, vDirectory, EMPTYDIRBLOCKS))) { - goto Bad_MakeDir; - } - /* Update the status for the parent dir */ + #if FS_STATS_DETAILED - Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId, - parentptr->disk.linkCount+1, client->InSameNetwork); + /* + * Remember when the data transfer started. + */ + TM_GetTimeOfDay(&xferStartTime, 0); +#endif /* FS_STATS_DETAILED */ + + /* Do the actual storing of the data */ +#if FS_STATS_DETAILED + errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, acall, + Pos, Length, FileLength, + (InStatus->Mask & AFS_FSYNC), + &bytesToXfer, &bytesXferred); #else - Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId, - parentptr->disk.linkCount+1); + errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, + acall, Pos, Length, FileLength, + (InStatus->Mask & AFS_FSYNC)); + if (errorCode && (!targetptr->changed_newTime)) + goto Bad_StoreData; #endif /* FS_STATS_DETAILED */ +#if FS_STATS_DETAILED + /* + * At this point, the data transfer is done, for good or ill. Remember + * when the transfer ended, bump the number of successes/failures, and + * integrate the transfer size and elapsed time into the stats. If the + * operation failed, we jump to the appropriate point. + */ + TM_GetTimeOfDay(&xferStopTime, 0); + FS_LOCK + (xferP->numXfers)++; + if (!errorCode) { + (xferP->numSuccesses)++; - /* Point to target's ACL buffer and copy the parent's ACL contents to it */ - assert((SetAccessList(&targetptr, &volptr, &newACL, &newACLSize, - &parentwhentargetnotdir, (AFSFid *)0, 0)) == 0); - assert(parentwhentargetnotdir == 0); - memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr)); + /* + * Bump the xfer sum by the number of bytes actually sent, NOT the + * target number. + */ + tot_bytesXferred += bytesXferred; + (xferP->sumBytes) += (tot_bytesXferred >> 10); + tot_bytesXferred &= 0x3FF; + if (bytesXferred < xferP->minBytes) + xferP->minBytes = bytesXferred; + if (bytesXferred > xferP->maxBytes) + xferP->maxBytes = bytesXferred; + + /* + * Tally the size of the object. Note: we tally the actual size, + * NOT the number of bytes that made it out over the wire. + */ + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0) + (xferP->count[0])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1) + (xferP->count[1])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2) + (xferP->count[2])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3) + (xferP->count[3])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4) + (xferP->count[4])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5) + (xferP->count[5])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6) + (xferP->count[6])++; + else + if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7) + (xferP->count[7])++; + else + (xferP->count[8])++; + + fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime); + fs_stats_AddTo((xferP->sumTime), elapsedTime); + fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) { + fs_stats_TimeAssign((xferP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) { + fs_stats_TimeAssign((xferP->maxTime), elapsedTime); + } + } + FS_UNLOCK - /* update the status for the target vnode */ - Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus, - parentptr, volptr, 0); + /* + * Finally, go off to tell our caller the bad news in case the + * store failed. + */ + if (errorCode && (!targetptr->changed_newTime)) + goto Bad_StoreData; +#endif /* FS_STATS_DETAILED */ - /* Actually create the New directory in the directory package */ - SetDirHandle(&dir, targetptr); - assert(!(MakeDir(&dir, OutFid, DirFid))); - DFlush(); - targetptr->disk.length = Length(&dir); + /* Update the status of the target's vnode */ + Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr, + volptr, 0); - /* set up return status */ - GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr); - GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL); + /* Get the updated File's status back to the caller */ + GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir); - /* convert the write lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, parentptr); - assert(!errorCode || errorCode == VSALVAGE); +Bad_StoreData: + /* Update and store volume/vnode and parent vnodes back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode)); - /* break call back on DirFid */ - BreakCallBack(client->host, DirFid, 0); + CallPostamble(tcon); - /* Return a callback promise to caller */ - SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack); +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (errorCode == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK + } +#endif /* FS_STATS_DETAILED */ -Bad_MakeDir: - /* Write the all modified vnodes (parent, new files) and volume back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); - FidZap(&dir); - FidZap(&parentdir); - ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode)); - return errorCode; + osi_auditU (acall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END); + return(errorCode); -} /*SAFSS_MakeDir*/ +} /*SRXAFS_StoreData*/ +afs_int32 SRXAFS_StoreData64 (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSStoreStatus *InStatus, + afs_uint64 Pos, + afs_uint64 Length, + afs_uint64 FileLength, + struct AFSFetchStatus *OutStatus, + struct AFSVolSync *Sync) +{ + int code; + afs_int32 tPos; + afs_int32 tLength; + afs_int32 tFileLength; -afs_int32 SRXAFS_MakeDir (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - struct AFSStoreStatus *InStatus, - struct AFSFid *OutFid, - struct AFSFetchStatus *OutFidStatus, - struct AFSFetchStatus *OutDirStatus, - struct AFSCallBack *CallBack, - struct AFSVolSync *Sync) +#ifdef AFS_64BIT_ENV + if (FileLength > 0x7fffffff) + return E2BIG; + tPos = Pos; + tLength = Length; + tFileLength = FileLength; +#else /* AFS_64BIT_ENV */ + if (FileLength.high) + return E2BIG; + tPos = Pos.low; + tLength = Length.low; + tFileLength = FileLength.low; +#endif /* AFS_64BIT_ENV */ + + code = SRXAFS_StoreData (acall, Fid, InStatus, tPos, tLength, tFileLength, + OutStatus, Sync); + return code; +} + +afs_int32 SRXAFS_StoreACL (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSOpaque *AccessList, + struct AFSFetchStatus *OutStatus, + struct AFSVolSync *Sync) { - afs_int32 code; + Vnode * targetptr = 0; /* pointer to input fid */ + Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */ + 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 */ + afs_int32 rights, anyrights; /* rights for this and any user */ struct rx_connection *tcon; + struct client *t_client; /* tmp ptr to client data */ + struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ #if FS_STATS_DETAILED struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ struct timeval opStartTime, @@ -3129,181 +3045,72 @@ afs_int32 SRXAFS_MakeDir (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]); FS_LOCK (opP->numOps)++; FS_UNLOCK TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ - if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_MakeDir; - - code = SAFSS_MakeDir (acall, DirFid, Name, InStatus, OutFid, - OutFidStatus, OutDirStatus, CallBack, Sync); - -Bad_MakeDir: - CallPostamble(tcon); - -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (code == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } - -#endif /* FS_STATS_DETAILED */ - - osi_auditU (acall, MakeDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END); - return code; - -} /*SRXAFS_MakeDir*/ - - -/* - * This routine is called exclusively by SRXAFS_RemoveDir(), and should be - * merged into it when possible. - */ -static afs_int32 -SAFSS_RemoveDir (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - struct AFSFetchStatus *OutDirStatus, - struct AFSVolSync *Sync) - -{ - Vnode * parentptr = 0; /* vnode of input Directory */ - Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ - Vnode * targetptr = 0; /* file to be deleted */ - AFSFid fileFid; /* area for Fid from the directory */ - 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 */ - afs_int32 rights, anyrights; /* rights for this and any user */ - Vnode debugvnode1, debugvnode2; - struct client *t_client; /* tmp ptr to client data */ - struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ - struct rx_connection *tcon = rx_ConnectionOf(acall); - - FidZero(&dir); + if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_StoreACL; /* Get ptr to client data for user Id for logging */ t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1, ("SAFS_RemoveDir %s, Did = %u.%d.%d, Host %s, Id %d\n", - Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique, + ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n", + Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val, inet_ntoa(logHostAddr), t_client->ViceId)); FS_LOCK - AFSCallStats.RemoveDir++, AFSCallStats.TotalCalls++; + AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++; FS_UNLOCK + + InStatus.Mask = 0; /* not storing any status */ + /* - * Get the vnode and volume for the parent dir along with the caller's - * rights to it + * Get associated volume/vnode for the target dir; caller's rights + * are also returned. */ - if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, + if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustBeDIR, &parentwhentargetnotdir, &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_RemoveDir; + goto Bad_StoreACL; } - debugvnode1 = *parentptr; /* set volume synchronization information */ SetVolumeSync(Sync, volptr); - /* Does the caller has delete (&write) access to the parent dir? */ - if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) { - goto Bad_RemoveDir; + /* Check if we have permission to change the dir's ACL */ + if ((errorCode = Check_PermissionRights(targetptr, client, rights, + CHK_STOREACL, &InStatus))) { + goto Bad_StoreACL; } - debugvnode2 = *parentptr; - /* Do the actual delete of the desired (empty) directory, Name */ - if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid, - Name, MustBeDIR))) { - goto Bad_RemoveDir; + /* Build and store the new Access List for the dir */ + if ((errorCode = RXStore_AccessList(targetptr, AccessList))) { + goto Bad_StoreACL; } - - /* Update the status for the parent dir; link count is also adjusted */ -#if FS_STATS_DETAILED - Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, - parentptr->disk.linkCount-1, client->InSameNetwork); -#else - Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, - parentptr->disk.linkCount-1); -#endif /* FS_STATS_DETAILED */ - - /* Return to the caller the updated parent dir status */ - GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL); - - /* - * Note: it is not necessary to break the callback on fileFid, since - * refcount is now 0, so no one should be able to refer to the dir - * any longer - */ - DeleteFileCallBacks(&fileFid); + + targetptr->changed_newTime = 1; /* status change of directory */ /* convert the write lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, parentptr); + VVnodeWriteToRead(&errorCode, targetptr); assert(!errorCode || errorCode == VSALVAGE); - /* break call back on DirFid and fileFid */ - BreakCallBack(client->host, DirFid, 0); - -Bad_RemoveDir: - /* Write the all modified vnodes (parent, new files) and volume back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); - FidZap(&dir); - ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode)); - return errorCode; - -} /*SAFSS_RemoveDir*/ - - -afs_int32 SRXAFS_RemoveDir (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - struct AFSFetchStatus *OutDirStatus, - struct AFSVolSync *Sync) -{ - afs_int32 code; - struct rx_connection *tcon; -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ - - /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ + /* break call backs on the directory */ + BreakCallBack(client->host, Fid, 0); - if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_RemoveDir; + /* Get the updated dir's status back to the caller */ + GetStatus(targetptr, OutStatus, rights, anyrights, 0); - code = SAFSS_RemoveDir (acall, DirFid, Name, OutDirStatus, Sync); - -Bad_RemoveDir: +Bad_StoreACL: + /* Update and store volume/vnode and parent vnodes back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode)); CallPostamble(tcon); #if FS_STATS_DETAILED TM_GetTimeOfDay(&opStopTime, 0); - if (code == 0) { + if (errorCode == 0) { FS_LOCK (opP->numSuccesses)++; fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); @@ -3317,93 +3124,101 @@ Bad_RemoveDir: } FS_UNLOCK } - #endif /* FS_STATS_DETAILED */ - osi_auditU (acall, RemoveDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END); - return code; + osi_auditU (acall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END); + return errorCode; -} /*SRXAFS_RemoveDir*/ +} /*SRXAFS_StoreACL*/ /* - * This routine is called exclusively by SRXAFS_SetLock(), and should be - * merged into it when possible. + * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and + * should be merged when possible. */ static afs_int32 -SAFSS_SetLock (struct rx_call *acall, - struct AFSFid *Fid, - ViceLockType type, - struct AFSVolSync *Sync) +SAFSS_StoreStatus (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSStoreStatus *InStatus, + struct AFSFetchStatus *OutStatus, + struct AFSVolSync *Sync) + { - Vnode * targetptr = 0; /* vnode of input file */ - Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ - int errorCode = 0; /* error code */ + Vnode * targetptr = 0; /* pointer to input 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 */ 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 */ - static char * locktype[2] = {"LockRead","LockWrite"}; struct rx_connection *tcon = rx_ConnectionOf(acall); - if (type != LockRead && type != LockWrite) { - errorCode = EINVAL; - goto Bad_SetLock; - } /* Get ptr to client data for user Id for logging */ t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1,("SAFS_SetLock type = %s Fid = %u.%d.%d, Host %s, Id %d\n", - locktype[(int)type], Fid->Volume, Fid->Vnode, Fid->Unique, + ViceLog(1, ("SAFS_StoreStatus, Fid = %u.%d.%d, Host %s, Id %d\n", + Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr), t_client->ViceId)); FS_LOCK - AFSCallStats.SetLock++, AFSCallStats.TotalCalls++; + AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++; FS_UNLOCK - /* - * Get the vnode and volume for the desired file along with the caller's - * rights to it + * Get volume/vnode for the target file; caller's rights to it are + * also returned */ if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK, &parentwhentargetnotdir, &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_SetLock; + goto Bad_StoreStatus; } /* set volume synchronization information */ SetVolumeSync(Sync, volptr); - /* Handle the particular type of set locking, type */ - errorCode = HandleLocking(targetptr, rights, type); - -Bad_SetLock: - /* Write the all modified vnodes (parent, new files) and volume back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + /* Check if the caller has proper permissions to store status to Fid */ + if ((errorCode = Check_PermissionRights(targetptr, client, rights, + CHK_STORESTATUS, InStatus))) { + goto Bad_StoreStatus; + } + /* + * Check for a symbolic link; we can't chmod these (otherwise could + * change a symlink to a mt pt or vice versa) + */ + if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) { + errorCode = EINVAL; + goto Bad_StoreStatus; + } - if ((errorCode == VREADONLY) && (type == LockRead)) - errorCode = 0; /* allow read locks on RO volumes without saving state */ + /* Update the status of the target's vnode */ + Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus, + (parentwhentargetnotdir ? + parentwhentargetnotdir : targetptr), volptr, 0); - ViceLog(2,("SAFS_SetLock returns %d\n", errorCode)); - return(errorCode); + /* convert the write lock to a read lock before breaking callbacks */ + VVnodeWriteToRead(&errorCode, targetptr); + assert(!errorCode || errorCode == VSALVAGE); -} /*SAFSS_SetLock*/ + /* Break call backs on Fid */ + BreakCallBack(client->host, Fid, 0); + /* Return the updated status back to caller */ + GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir); -afs_int32 SRXAFS_OldSetLock(struct rx_call *acall, - struct AFSFid *Fid, - ViceLockType type, - struct AFSVolSync *Sync) -{ - return SRXAFS_SetLock(acall, Fid, type, Sync); +Bad_StoreStatus: + /* Update and store volume/vnode and parent vnodes back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode)); + return errorCode; -} /*SRXAFS_OldSetLock*/ +} /*SAFSS_StoreStatus*/ -afs_int32 SRXAFS_SetLock (struct rx_call *acall, - struct AFSFid *Fid, - ViceLockType type, - struct AFSVolSync *Sync) +afs_int32 SRXAFS_StoreStatus (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSStoreStatus *InStatus, + struct AFSFetchStatus *OutStatus, + struct AFSVolSync *Sync) { afs_int32 code; struct rx_connection *tcon; @@ -3417,7 +3232,7 @@ afs_int32 SRXAFS_SetLock (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]); FS_LOCK (opP->numOps)++; FS_UNLOCK @@ -3425,15 +3240,15 @@ afs_int32 SRXAFS_SetLock (struct rx_call *acall, #endif /* FS_STATS_DETAILED */ if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_SetLock; + goto Bad_StoreStatus; - code = SAFSS_SetLock (acall, Fid, type, Sync); - -Bad_SetLock: + code = SAFSS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync); + +Bad_StoreStatus: CallPostamble(tcon); #if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); + TM_GetTimeOfDay(&opStopTime, 0); if (code == 0) { FS_LOCK (opP->numSuccesses)++; @@ -3448,83 +3263,119 @@ Bad_SetLock: } FS_UNLOCK } + #endif /* FS_STATS_DETAILED */ - osi_auditU (acall, SetLockEvent, code, AUD_FID, Fid, AUD_LONG, type, AUD_END); + osi_auditU (acall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END); return code; -} /*SRXAFS_SetLock*/ +} /*SRXAFS_StoreStatus*/ /* - * This routine is called exclusively by SRXAFS_ExtendLock(), and should be - * merged into it when possible. + * This routine is called exclusively by SRXAFS_RemoveFile(), and should be + * merged in when possible. */ -static afs_int32 -SAFSS_ExtendLock (struct rx_call *acall, - struct AFSFid *Fid, +static afs_int32 +SAFSS_RemoveFile (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + struct AFSFetchStatus *OutDirStatus, struct AFSVolSync *Sync) - { - Vnode * targetptr = 0; /* vnode of input file */ + Vnode * parentptr = 0; /* vnode of input Directory */ Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ - int errorCode = 0; /* error code */ + Vnode * targetptr = 0; /* file to be deleted */ Volume * volptr = 0; /* pointer to the volume header */ + 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 */ 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 */ struct rx_connection *tcon = rx_ConnectionOf(acall); + FidZero(&dir); /* Get ptr to client data for user Id for logging */ t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1,("SAFS_ExtendLock Fid = %u.%d.%d, Host %s, Id %d\n", - Fid->Volume, Fid->Vnode, Fid->Unique, - inet_ntoa(logHostAddr), t_client->ViceId)); + ViceLog(1, ("SAFS_RemoveFile %s, Did = %u.%d.%d, Host %s, Id %d\n", + Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); FS_LOCK - AFSCallStats.ExtendLock++, AFSCallStats.TotalCalls++; + AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++; FS_UNLOCK /* - * Get the vnode and volume for the desired file along with the caller's - * rights to it + * Get volume/vnode for the parent dir; caller's access rights are + * also returned */ - if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, - DONTCHECK, &parentwhentargetnotdir, + if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, + MustBeDIR, &parentwhentargetnotdir, &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_ExtendLock; + goto Bad_RemoveFile; } - /* set volume synchronization information */ SetVolumeSync(Sync, volptr); - /* Handle the actual lock extension */ - errorCode = HandleLocking(targetptr, rights, LockExtend); + /* Does the caller has delete (& write) access to the parent directory? */ + if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) { + goto Bad_RemoveFile; + } -Bad_ExtendLock: - /* Put back file's vnode and volume */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + /* Actually delete the desired file */ + if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, + &fileFid, Name, MustNOTBeDIR))) { + goto Bad_RemoveFile; + } - if ((errorCode == VREADONLY)) /* presumably, we already granted this lock */ - errorCode = 0; /* under our generous policy re RO vols */ + /* Update the vnode status of the parent dir */ +#if FS_STATS_DETAILED + Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, + parentptr->disk.linkCount, client->InSameNetwork); +#else + Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, + parentptr->disk.linkCount); +#endif /* FS_STATS_DETAILED */ - ViceLog(2,("SAFS_ExtendLock returns %d\n", errorCode)); - return(errorCode); + /* Return the updated parent dir's status back to caller */ + GetStatus(parentptr, OutDirStatus, rights, anyrights, 0); -} /*SAFSS_ExtendLock*/ + /* Handle internal callback state for the parent and the deleted file */ + if (targetptr->disk.linkCount == 0) { + /* no references left, discard entry */ + DeleteFileCallBacks(&fileFid); + /* convert the parent lock to a read lock before breaking callbacks */ + VVnodeWriteToRead(&errorCode, parentptr); + assert(!errorCode || errorCode == VSALVAGE); + } else { + /* convert the parent lock to a read lock before breaking callbacks */ + VVnodeWriteToRead(&errorCode, parentptr); + assert(!errorCode || errorCode == VSALVAGE); + /* convert the target lock to a read lock before breaking callbacks */ + VVnodeWriteToRead(&errorCode, targetptr); + assert(!errorCode || errorCode == VSALVAGE); + /* tell all the file has changed */ + BreakCallBack(client->host, &fileFid, 1); + } + /* break call back on the directory */ + BreakCallBack(client->host, DirFid, 0); -afs_int32 SRXAFS_OldExtendLock (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSVolSync *Sync) -{ - return SRXAFS_ExtendLock(acall, Fid, Sync); +Bad_RemoveFile: + /* Update and store volume/vnode and parent vnodes back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); + FidZap(&dir); + ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode)); + return errorCode; -} /*SRXAFS_OldExtendLock*/ +} /*SAFSS_RemoveFile*/ -afs_int32 SRXAFS_ExtendLock (struct rx_call *acall, - struct AFSFid *Fid, +afs_int32 SRXAFS_RemoveFile (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + struct AFSFetchStatus *OutDirStatus, struct AFSVolSync *Sync) { afs_int32 code; @@ -3539,7 +3390,7 @@ afs_int32 SRXAFS_ExtendLock (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_EXTENDLOCK]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]); FS_LOCK (opP->numOps)++; FS_UNLOCK @@ -3547,11 +3398,11 @@ afs_int32 SRXAFS_ExtendLock (struct rx_call *acall, #endif /* FS_STATS_DETAILED */ if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_ExtendLock; + goto Bad_RemoveFile; - code = SAFSS_ExtendLock (acall, Fid, Sync); + code = SAFSS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync); -Bad_ExtendLock: +Bad_RemoveFile: CallPostamble(tcon); #if FS_STATS_DETAILED @@ -3573,91 +3424,124 @@ Bad_ExtendLock: #endif /* FS_STATS_DETAILED */ - osi_auditU (acall, ExtendLockEvent, code, AUD_FID, Fid , AUD_END); + osi_auditU (acall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END); return code; -} /*SRXAFS_ExtendLock*/ +} /*SRXAFS_RemoveFile*/ /* - * This routine is called exclusively by SRXAFS_ReleaseLock(), and should be - * merged into it when possible. + * This routine is called exclusively from SRXAFS_CreateFile(), and should + * be merged in when possible. */ -static afs_int32 -SAFSS_ReleaseLock (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSVolSync *Sync) - +static afs_int32 +SAFSS_CreateFile (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + struct AFSStoreStatus *InStatus, + struct AFSFid *OutFid, + struct AFSFetchStatus *OutFidStatus, + struct AFSFetchStatus *OutDirStatus, + struct AFSCallBack *CallBack, + struct AFSVolSync *Sync) { - Vnode * targetptr = 0; /* vnode of input file */ + Vnode * parentptr = 0; /* vnode of input Directory */ + Vnode * targetptr = 0; /* vnode of the new file */ Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ - int errorCode = 0; /* error code */ 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 */ 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 */ struct rx_connection *tcon = rx_ConnectionOf(acall); + FidZero(&dir); + /* Get ptr to client data for user Id for logging */ t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); - ViceLog(1,("SAFS_ReleaseLock Fid = %u.%d.%d, Host %s, Id %d\n", - Fid->Volume, Fid->Vnode, Fid->Unique, + ViceLog(1, ("SAFS_CreateFile %s, Did = %u.%d.%d, Host %s, Id %d\n", + Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique, inet_ntoa(logHostAddr), t_client->ViceId)); FS_LOCK - AFSCallStats.ReleaseLock++, AFSCallStats.TotalCalls++; + AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++; FS_UNLOCK + if (!FileNameOK(Name)) { + errorCode = EINVAL; + goto Bad_CreateFile; + } + /* - * Get the vnode and volume for the desired file along with the caller's - * rights to it + * Get associated volume/vnode for the parent dir; caller long are + * also returned */ - if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, - DONTCHECK, &parentwhentargetnotdir, + if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, + MustBeDIR, &parentwhentargetnotdir, &client, WRITE_LOCK, &rights, &anyrights))) { - goto Bad_ReleaseLock; + goto Bad_CreateFile; } /* set volume synchronization information */ SetVolumeSync(Sync, volptr); - /* Handle the actual lock release */ - if ((errorCode = HandleLocking(targetptr, rights, LockRelease))) - goto Bad_ReleaseLock; - - /* if no more locks left, a callback would be triggered here */ - if (targetptr->disk.lock.lockCount <= 0) { - /* convert the write lock to a read lock before breaking callbacks */ - VVnodeWriteToRead(&errorCode, targetptr); - assert(!errorCode || errorCode == VSALVAGE); - BreakCallBack(client->host, Fid, 0); + /* Can we write (and insert) onto the parent directory? */ + if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) { + goto Bad_CreateFile; + } + /* get a new vnode for the file to be created and set it up */ + if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr, + Name, OutFid, vFile, nBlocks(0)))) { + goto Bad_CreateFile; } -Bad_ReleaseLock: - /* Put back file's vnode and volume */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - - if ((errorCode == VREADONLY)) /* presumably, we already granted this lock */ - errorCode = 0; /* under our generous policy re RO vols */ + /* update the status of the parent vnode */ +#if FS_STATS_DETAILED + Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, + parentptr->disk.linkCount, client->InSameNetwork); +#else + Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, + parentptr->disk.linkCount); +#endif /* FS_STATS_DETAILED */ - ViceLog(2,("SAFS_ReleaseLock returns %d\n", errorCode)); - return(errorCode); + /* update the status of the new file's vnode */ + Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus, + parentptr, volptr, 0); -} /*SAFSS_ReleaseLock*/ + /* set up the return status for the parent dir and the newly created file */ + GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr); + GetStatus(parentptr, OutDirStatus, rights, anyrights, 0); + /* convert the write lock to a read lock before breaking callbacks */ + VVnodeWriteToRead(&errorCode, parentptr); + assert(!errorCode || errorCode == VSALVAGE); + + /* break call back on parent dir */ + BreakCallBack(client->host, DirFid, 0); -afs_int32 SRXAFS_OldReleaseLock (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSVolSync *Sync) -{ - return SRXAFS_ReleaseLock(acall, Fid, Sync); + /* Return a callback promise for the newly created file to the caller */ + SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack); -} /*SRXAFS_OldReleaseLock*/ +Bad_CreateFile: + /* Update and store volume/vnode and parent vnodes back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); + FidZap(&dir); + ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode)); + return errorCode; +} /*SAFSS_CreateFile*/ -afs_int32 SRXAFS_ReleaseLock (struct rx_call *acall, - struct AFSFid *Fid, - struct AFSVolSync *Sync) + +afs_int32 SRXAFS_CreateFile (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + struct AFSStoreStatus *InStatus, + struct AFSFid *OutFid, + struct AFSFetchStatus *OutFidStatus, + struct AFSFetchStatus *OutDirStatus, + struct AFSCallBack *CallBack, + struct AFSVolSync *Sync) { afs_int32 code; struct rx_connection *tcon; @@ -3671,7 +3555,7 @@ afs_int32 SRXAFS_ReleaseLock (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RELEASELOCK]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]); FS_LOCK (opP->numOps)++; FS_UNLOCK @@ -3679,11 +3563,12 @@ afs_int32 SRXAFS_ReleaseLock (struct rx_call *acall, #endif /* FS_STATS_DETAILED */ if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_ReleaseLock; + goto Bad_CreateFile; - code = SAFSS_ReleaseLock (acall, Fid, Sync); - -Bad_ReleaseLock: + code = SAFSS_CreateFile (acall, DirFid, Name, InStatus, OutFid, + OutFidStatus, OutDirStatus, CallBack, Sync); + +Bad_CreateFile: CallPostamble(tcon); #if FS_STATS_DETAILED @@ -3702,393 +3587,433 @@ Bad_ReleaseLock: } FS_UNLOCK } - #endif /* FS_STATS_DETAILED */ - osi_auditU (acall, ReleaseLockEvent, code, AUD_FID, Fid , AUD_END); + osi_auditU (acall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END); return code; -} /*SRXAFS_ReleaseLock*/ +} /*SRXAFS_CreateFile*/ -void SetSystemStats(struct AFSStatistics *stats) +/* + * This routine is called exclusively from SRXAFS_Rename(), and should be + * merged in when possible. + */ +static afs_int32 +SAFSS_Rename (struct rx_call *acall, + struct AFSFid *OldDirFid, + char *OldName, + struct AFSFid *NewDirFid, + char *NewName, + struct AFSFetchStatus *OutOldDirStatus, + struct AFSFetchStatus *OutNewDirStatus, + struct AFSVolSync *Sync) { - /* Fix this sometime soon.. */ - /* Because hey, it's not like we have a network monitoring protocol... */ - struct timeval time; - - /* this works on all system types */ - TM_GetTimeOfDay(&time, 0); - stats->CurrentTime = time.tv_sec; -} /*SetSystemStats*/ + Vnode * oldvptr = 0; /* vnode of the old Directory */ + Vnode * newvptr = 0; /* vnode of the new Directory */ + Vnode * fileptr = 0; /* vnode of the file to move */ + Vnode * newfileptr = 0; /* vnode of the file to delete */ + Vnode * testvptr = 0; /* used in directory tree walk */ + Vnode * parent = 0; /* parent for use in SetAccessList */ + int errorCode = 0; /* error code */ + int fileCode = 0; /* used when writing Vnodes */ + VnodeId testnode; /* used in directory tree walk */ + AFSFid fileFid; /* Fid of file to move */ + AFSFid newFileFid; /* Fid of new file */ + DirHandle olddir; /* Handle for dir package I/O */ + DirHandle newdir; /* Handle for dir package I/O */ + 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 */ + afs_int32 rights, anyrights; /* rights for this and any user */ + afs_int32 newrights; /* rights for this user */ + afs_int32 newanyrights; /* rights for any user */ + int doDelete; /* deleted the rename target (ref count now 0) */ + int code; + struct client *t_client; /* tmp ptr to client data */ + struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ + struct rx_connection *tcon = rx_ConnectionOf(acall); -void SetAFSStats(struct AFSStatistics *stats) -{ - extern afs_int32 StartTime, CurrentConnections; - int seconds; + FidZero(&olddir); + FidZero(&newdir); + FidZero(&filedir); + FidZero(&newfiledir); + /* Get ptr to client data for user Id for logging */ + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); + ViceLog(1, ("SAFS_Rename %s to %s, Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n", + OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode, + OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode, + NewDirFid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); FS_LOCK - stats->CurrentMsgNumber = 0; - stats->OldestMsgNumber = 0; - stats->StartTime = StartTime; - stats->CurrentConnections = CurrentConnections; - stats->TotalAFSCalls = AFSCallStats.TotalCalls; - stats->TotalFetchs = AFSCallStats.FetchData+AFSCallStats.FetchACL+AFSCallStats.FetchStatus; - stats->FetchDatas = AFSCallStats.FetchData; - stats->FetchedBytes = AFSCallStats.TotalFetchedBytes; - seconds = AFSCallStats.AccumFetchTime/1000; - if (seconds <= 0) seconds = 1; - stats->FetchDataRate = AFSCallStats.TotalFetchedBytes/seconds; - stats->TotalStores = AFSCallStats.StoreData+AFSCallStats.StoreACL+AFSCallStats.StoreStatus; - stats->StoreDatas = AFSCallStats.StoreData; - stats->StoredBytes = AFSCallStats.TotalStoredBytes; - seconds = AFSCallStats.AccumStoreTime/1000; - if (seconds <= 0) seconds = 1; - stats->StoreDataRate = AFSCallStats.TotalStoredBytes/seconds; -#ifdef AFS_NT40_ENV - stats->ProcessSize = -1; /* TODO: */ -#else - stats->ProcessSize = (afs_int32)((long) sbrk(0) >> 10); -#endif + AFSCallStats.Rename++, AFSCallStats.TotalCalls++; FS_UNLOCK - h_GetWorkStats((int *)&(stats->WorkStations),(int *)&(stats->ActiveWorkStations), - (int *)0, (afs_int32)(FT_ApproxTime())-(15*60)); - -} /*SetAFSStats*/ - -/* Get disk related information from all AFS partitions. */ - -void SetVolumeStats(struct AFSStatistics *stats) -{ - struct DiskPartition * part; - int i = 0; - - for (part = DiskPartitionList; part && i < AFS_MSTATDISKS; part = part->next) { - stats->Disks[i].TotalBlocks = part->totalUsable; - stats->Disks[i].BlocksAvailable = part->free; - memset(stats->Disks[i].Name, 0, AFS_DISKNAMESIZE); - strncpy(stats->Disks[i].Name, part->name, AFS_DISKNAMESIZE); - i++; + if (!FileNameOK(NewName)) { + errorCode = EINVAL; + goto Bad_Rename; } - while (i < AFS_MSTATDISKS) { - stats->Disks[i].TotalBlocks = -1; - i++; + if (OldDirFid->Volume != NewDirFid->Volume) { + DFlush(); + errorCode = EXDEV; + goto Bad_Rename; + } + if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) || + (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) || + (strlen(NewName) == 0) || (strlen(OldName) == 0) ) { + DFlush(); + errorCode = EINVAL; + goto Bad_Rename; } -} /*SetVolumeStats*/ - -afs_int32 SRXAFS_GetStatistics (struct rx_call *acall, - struct ViceStatistics *Statistics) -{ - afs_int32 code; - struct rx_connection *tcon; -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ - /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ + if (OldDirFid->Vnode <= NewDirFid->Vnode) { + if (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, + &oldvptr, MustBeDIR, &parent, + &client, WRITE_LOCK, &rights, + &anyrights)) { + DFlush(); + goto Bad_Rename; + } + if (OldDirFid->Vnode == NewDirFid->Vnode) { + newvptr = oldvptr; + newrights = rights, newanyrights = anyrights; + } + else + if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr, + &newvptr, MustBeDIR, &parent, + &client, WRITE_LOCK, &newrights, + &newanyrights))) { + DFlush(); + goto Bad_Rename; + } + } + else { + if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr, + &newvptr, MustBeDIR, &parent, + &client, WRITE_LOCK, &newrights, + &newanyrights))) { + DFlush(); + goto Bad_Rename; + } + if ((errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr, + MustBeDIR, &parent, &client, WRITE_LOCK, + &rights, &anyrights))) { + DFlush(); + goto Bad_Rename; + } + } - if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon))) - goto Bad_GetStatistics; + /* set volume synchronization information */ + SetVolumeSync(Sync, volptr); - ViceLog(1, ("SAFS_GetStatistics Received\n")); - FS_LOCK - AFSCallStats.GetStatistics++, AFSCallStats.TotalCalls++; - FS_UNLOCK - memset(Statistics, 0, sizeof(*Statistics)); - SetAFSStats(Statistics); - SetVolumeStats(Statistics); - SetSystemStats(Statistics); - -Bad_GetStatistics: - CallPostamble(tcon); + if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) { + goto Bad_Rename; + } + if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) { + goto Bad_Rename; + } -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (code == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK + /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second + * call to CopyOnWrite returns error, it is not necessary to revert back + * the effects of the first call because the contents of the volume is + * not modified, it is only replicated. + */ + if (oldvptr->disk.cloned) + { + ViceLog(25, ("Rename : calling CopyOnWrite on old dir\n")); + if ( ( errorCode = CopyOnWrite(oldvptr, volptr) ) ) + goto Bad_Rename; + } + SetDirHandle(&olddir, oldvptr); + if (newvptr->disk.cloned) + { + ViceLog(25, ("Rename : calling CopyOnWrite on new dir\n")); + if ( ( errorCode = CopyOnWrite(newvptr, volptr) ) ) + goto Bad_Rename; } -#endif /* FS_STATS_DETAILED */ - return code; + SetDirHandle(&newdir, newvptr); -} /*SRXAFS_GetStatistics*/ + /* Lookup the file to delete its vnode */ + if (Lookup(&olddir, OldName, &fileFid)) { + errorCode = ENOENT; + goto Bad_Rename; + } + if (fileFid.Vnode == oldvptr->vnodeNumber || + fileFid.Vnode == newvptr->vnodeNumber) { + errorCode = FSERR_ELOOP; + goto Bad_Rename; + } + fileFid.Volume = V_id(volptr); + fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK); + if (errorCode != 0) { + ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode)); + VTakeOffline (volptr); + goto Bad_Rename; + } + if (fileptr->disk.uniquifier != fileFid.Unique) { + ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName)); + VTakeOffline (volptr); + errorCode = EIO; + goto Bad_Rename; + } + if (fileptr->disk.type != vDirectory && + oldvptr != newvptr && + fileptr->disk.linkCount != 1) { + /* + * Hard links exist to this file - cannot move one of the links to + * a new directory because of AFS restrictions (this is the same + * reason that links cannot be made across directories, i.e. + * access lists) + */ + errorCode = EXDEV; + goto Bad_Rename; + } -/*------------------------------------------------------------------------ - * EXPORTED SRXAFS_XStatsVersion - * - * Description: - * Routine called by the server-side RPC interface to implement - * pulling out the xstat version number for the File Server. - * - * Arguments: - * a_versionP : Ptr to the version number variable to set. - * - * Returns: - * 0 (always) - * - * Environment: - * Nothing interesting. - * - * Side Effects: - * As advertised. - *------------------------------------------------------------------------*/ + /* Lookup the new file */ + if (!(Lookup(&newdir, NewName, &newFileFid))) { + if (readonlyServer) { + errorCode = VREADONLY; + goto Bad_Rename; + } + if (!(newrights & PRSFS_DELETE)) { + errorCode = EACCES; + goto Bad_Rename; + } + if (newFileFid.Vnode == oldvptr->vnodeNumber || + newFileFid.Vnode == newvptr->vnodeNumber || + newFileFid.Vnode == fileFid.Vnode) { + errorCode = EINVAL; + goto Bad_Rename; + } + newFileFid.Volume = V_id(volptr); + newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK); + if (errorCode != 0) { + ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode)); + VTakeOffline (volptr); + goto Bad_Rename; + } + if (fileptr->disk.uniquifier != fileFid.Unique) { + ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName)); + VTakeOffline (volptr); + errorCode = EIO; + goto Bad_Rename; + } + SetDirHandle(&newfiledir, newfileptr); + /* Now check that we're moving directories over directories properly, etc. + * return proper POSIX error codes: + * if fileptr is a file and new is a dir: EISDIR. + * if fileptr is a dir and new is a file: ENOTDIR. + * Also, dir to be removed must be empty, of course. + */ + if (newfileptr->disk.type == vDirectory) { + if (fileptr->disk.type != vDirectory) { + errorCode = EISDIR; + goto Bad_Rename; + } + if ((IsEmpty(&newfiledir))) { + errorCode = EEXIST; + goto Bad_Rename; + } + } + else { + if (fileptr->disk.type == vDirectory) { + errorCode = ENOTDIR; + goto Bad_Rename; + } + } + } -afs_int32 SRXAFS_XStatsVersion(struct rx_call *a_call, afs_int32 *a_versionP) -{ /*SRXAFS_XStatsVersion*/ + /* + * ok - now we check that the old name is not above new name in the + * directory structure. This is to prevent removing a subtree alltogether + */ + if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) { + for (testnode = newvptr->disk.parent; testnode != 0;) { + if (testnode == oldvptr->vnodeNumber) { + testnode = oldvptr->disk.parent; + continue; + } + if ((testnode == fileptr->vnodeNumber) || + (testnode == newvptr->vnodeNumber)) { + errorCode = FSERR_ELOOP; + goto Bad_Rename; + } + if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) { + errorCode = FSERR_ELOOP; + goto Bad_Rename; + } + testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK); + assert(errorCode == 0); + testnode = testvptr->disk.parent; + VPutVnode(&errorCode, testvptr); + assert(errorCode == 0); + } + } + /* Do the CopyonWrite first before modifying anything else. Copying is + * required because we may have to change entries for .. + */ + if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) ) + { + ViceLog(25, ("Rename : calling CopyOnWrite on target dir\n")); + if ( ( errorCode = CopyOnWrite(fileptr, volptr) ) ) + goto Bad_Rename; + } -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ + /* If the new name exists already, delete it and the file it points to */ + doDelete = 0; + if (newfileptr) { + /* Delete NewName from its directory */ + code = Delete(&newdir, NewName); + assert(code == 0); + /* Drop the link count */ + newfileptr->disk.linkCount--; + if (newfileptr->disk.linkCount == 0) { /* Link count 0 - delete */ + VAdjustDiskUsage(&errorCode, volptr, + -(int)nBlocks(newfileptr->disk.length), 0); + if (VN_GET_INO(newfileptr)) { + IH_REALLYCLOSE(newfileptr->handle); + errorCode = IH_DEC(V_linkHandle(volptr), + VN_GET_INO(newfileptr), + V_parentId(volptr)); + IH_RELEASE(newfileptr->handle); + if (errorCode == -1) { + ViceLog(0, ("Del: inode=%s, name=%s, errno=%d\n", + PrintInode(NULL, VN_GET_INO(newfileptr)), + NewName, errno)); + if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO)) + ViceLog(0, ("Do we need to fsck?")); + } + } + VN_SET_INO(newfileptr, (Inode)0); + newfileptr->delete = 1; /* Mark NewName vnode to delete */ + doDelete = 1; + } else { + /* Link count did not drop to zero. + * Mark NewName vnode as changed - updates stime. + */ + newfileptr->changed_newTime = 1; + } + } + /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. + * If the create below fails, and the delete above worked, we have + * removed the new name and not replaced it. This is not very likely, + * but possible. We could try to put the old file back, but it is + * highly unlikely that it would work since it would involve issuing + * another create. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_XSTATSVERSION]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ + if ((errorCode = Create(&newdir,(char *) NewName, &fileFid))) + goto Bad_Rename; - *a_versionP = AFS_XSTAT_VERSION; + /* Delete the old name */ + assert(Delete(&olddir,(char *) OldName) == 0); + /* if the directory length changes, reflect it in the statistics */ #if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_LOCK - (opP->numSuccesses)++; - FS_UNLOCK + Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId, + oldvptr->disk.linkCount, client->InSameNetwork); + Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId, + newvptr->disk.linkCount, client->InSameNetwork); +#else + Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId, + oldvptr->disk.linkCount); + Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId, + newvptr->disk.linkCount); #endif /* FS_STATS_DETAILED */ - return(0); - -} /*SRXAFS_XStatsVersion*/ - + if (oldvptr == newvptr) + oldvptr->disk.dataVersion--; /* Since it was bumped by 2! */ -/*------------------------------------------------------------------------ - * PRIVATE FillPerfValues - * - * Description: - * Routine called to fill a regular performance data structure. - * - * Arguments: - * a_perfP : Ptr to perf structure to fill - * - * Returns: - * Nothing. - * - * Environment: - * Various collections need this info, so the guts were put in - * this separate routine. - * - * Side Effects: - * As advertised. - *------------------------------------------------------------------------*/ + fileptr->disk.parent = newvptr->vnodeNumber; + fileptr->changed_newTime = 1; /* status change of moved file */ -static void FillPerfValues(struct afs_PerfStats *a_perfP) -{ /*FillPerfValues*/ + /* if we are dealing with a rename of a directory */ + if (fileptr->disk.type == vDirectory) { + assert(!fileptr->disk.cloned); + SetDirHandle(&filedir, fileptr); + /* fix .. to point to the correct place */ + Delete(&filedir, ".."); /* No assert--some directories may be bad */ + assert(Create(&filedir, "..", NewDirFid) == 0); + fileptr->disk.dataVersion++; + /* if the parent directories are different the link counts have to be */ + /* changed due to .. in the renamed directory */ + if (oldvptr != newvptr) { + oldvptr->disk.linkCount--; + newvptr->disk.linkCount++; + } + } - int dir_Buffers; /*# buffers in use by dir package*/ - int dir_Calls; /*# read calls in dir package*/ - int dir_IOs; /*# I/O ops in dir package*/ + /* set up return status */ + GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, 0); + GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, 0); + if (newfileptr && doDelete) { + DeleteFileCallBacks(&newFileFid); /* no other references */ + } - /* - * Vnode cache section. - */ - a_perfP->vcache_L_Entries = VnodeClassInfo[vLarge].cacheSize; - a_perfP->vcache_L_Allocs = VnodeClassInfo[vLarge].allocs; - a_perfP->vcache_L_Gets = VnodeClassInfo[vLarge].gets; - a_perfP->vcache_L_Reads = VnodeClassInfo[vLarge].reads; - a_perfP->vcache_L_Writes = VnodeClassInfo[vLarge].writes; - a_perfP->vcache_S_Entries = VnodeClassInfo[vSmall].cacheSize; - a_perfP->vcache_S_Allocs = VnodeClassInfo[vSmall].allocs; - a_perfP->vcache_S_Gets = VnodeClassInfo[vSmall].gets; - a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads; - a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes; - a_perfP->vcache_H_Entries = VolumeCacheSize; - a_perfP->vcache_H_Gets = VolumeGets; - a_perfP->vcache_H_Replacements = VolumeReplacements; - - /* - * Directory section. - */ - DStat(&dir_Buffers, &dir_Calls, &dir_IOs); - a_perfP->dir_Buffers = (afs_int32) dir_Buffers; - a_perfP->dir_Calls = (afs_int32 )dir_Calls; - a_perfP->dir_IOs = (afs_int32) dir_IOs; - - /* - * Rx section. - */ - a_perfP->rx_packetRequests = - (afs_int32) rx_stats.packetRequests; - a_perfP->rx_noPackets_RcvClass = - (afs_int32) rx_stats.receivePktAllocFailures; - a_perfP->rx_noPackets_SendClass = - (afs_int32) rx_stats.sendPktAllocFailures; - a_perfP->rx_noPackets_SpecialClass = - (afs_int32) rx_stats.specialPktAllocFailures; - a_perfP->rx_socketGreedy = - (afs_int32) rx_stats.socketGreedy; - a_perfP->rx_bogusPacketOnRead = - (afs_int32) rx_stats.bogusPacketOnRead; - a_perfP->rx_bogusHost = - (afs_int32) rx_stats.bogusHost; - a_perfP->rx_noPacketOnRead = - (afs_int32) rx_stats.noPacketOnRead; - a_perfP->rx_noPacketBuffersOnRead = - (afs_int32) rx_stats.noPacketBuffersOnRead; - a_perfP->rx_selects = - (afs_int32) rx_stats.selects; - a_perfP->rx_sendSelects = - (afs_int32) rx_stats.sendSelects; - a_perfP->rx_packetsRead_RcvClass = - (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_RECEIVE]; - a_perfP->rx_packetsRead_SendClass = - (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SEND]; - a_perfP->rx_packetsRead_SpecialClass = - (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SPECIAL]; - a_perfP->rx_dataPacketsRead = - (afs_int32) rx_stats.dataPacketsRead; - a_perfP->rx_ackPacketsRead = - (afs_int32) rx_stats.ackPacketsRead; - a_perfP->rx_dupPacketsRead = - (afs_int32) rx_stats.dupPacketsRead; - a_perfP->rx_spuriousPacketsRead = - (afs_int32) rx_stats.spuriousPacketsRead; - a_perfP->rx_packetsSent_RcvClass = - (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_RECEIVE]; - a_perfP->rx_packetsSent_SendClass = - (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SEND]; - a_perfP->rx_packetsSent_SpecialClass = - (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SPECIAL]; - a_perfP->rx_ackPacketsSent = - (afs_int32) rx_stats.ackPacketsSent; - a_perfP->rx_pingPacketsSent = - (afs_int32) rx_stats.pingPacketsSent; - a_perfP->rx_abortPacketsSent = - (afs_int32) rx_stats.abortPacketsSent; - a_perfP->rx_busyPacketsSent = - (afs_int32) rx_stats.busyPacketsSent; - a_perfP->rx_dataPacketsSent = - (afs_int32) rx_stats.dataPacketsSent; - a_perfP->rx_dataPacketsReSent = - (afs_int32) rx_stats.dataPacketsReSent; - a_perfP->rx_dataPacketsPushed = - (afs_int32) rx_stats.dataPacketsPushed; - a_perfP->rx_ignoreAckedPacket = - (afs_int32) rx_stats.ignoreAckedPacket; - a_perfP->rx_totalRtt_Sec = - (afs_int32) rx_stats.totalRtt.sec; - a_perfP->rx_totalRtt_Usec = - (afs_int32) rx_stats.totalRtt.usec; - a_perfP->rx_minRtt_Sec = - (afs_int32) rx_stats.minRtt.sec; - a_perfP->rx_minRtt_Usec = - (afs_int32) rx_stats.minRtt.usec; - a_perfP->rx_maxRtt_Sec = - (afs_int32) rx_stats.maxRtt.sec; - a_perfP->rx_maxRtt_Usec = - (afs_int32) rx_stats.maxRtt.usec; - a_perfP->rx_nRttSamples = - (afs_int32) rx_stats.nRttSamples; - a_perfP->rx_nServerConns = - (afs_int32) rx_stats.nServerConns; - a_perfP->rx_nClientConns = - (afs_int32) rx_stats.nClientConns; - a_perfP->rx_nPeerStructs = - (afs_int32) rx_stats.nPeerStructs; - a_perfP->rx_nCallStructs = - (afs_int32) rx_stats.nCallStructs; - a_perfP->rx_nFreeCallStructs = - (afs_int32) rx_stats.nFreeCallStructs; - - a_perfP->host_NumHostEntries = HTs; - a_perfP->host_HostBlocks = HTBlocks; - h_GetHostNetStats(&(a_perfP->host_NonDeletedHosts), - &(a_perfP->host_HostsInSameNetOrSubnet), - &(a_perfP->host_HostsInDiffSubnet), - &(a_perfP->host_HostsInDiffNetwork)); - a_perfP->host_NumClients = CEs; - a_perfP->host_ClientBlocks = CEBlocks; - - a_perfP->sysname_ID = afs_perfstats.sysname_ID; + DFlush(); -} /*FillPerfValues*/ + /* convert the write locks to a read locks before breaking callbacks */ + VVnodeWriteToRead(&errorCode, newvptr); + assert(!errorCode || errorCode == VSALVAGE); + if (oldvptr != newvptr) { + VVnodeWriteToRead(&errorCode, oldvptr); + assert(!errorCode || errorCode == VSALVAGE); + } + if (newfileptr && !doDelete) { + /* convert the write lock to a read lock before breaking callbacks */ + VVnodeWriteToRead(&errorCode, newfileptr); + assert(!errorCode || errorCode == VSALVAGE); + } + /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid */ + BreakCallBack(client->host, NewDirFid, 0); + if (oldvptr != newvptr) { + BreakCallBack(client->host, OldDirFid, 0); + if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */ + BreakCallBack(client->host, &fileFid, 0); + } + if (newfileptr) { + /* Note: it is not necessary to break the callback */ + if (doDelete) + DeleteFileCallBacks(&newFileFid); /* no other references */ + else + /* other's still exist (with wrong link count) */ + BreakCallBack(client->host, &newFileFid, 1); + } -/*------------------------------------------------------------------------ - * EXPORTED SRXAFS_GetXStats - * - * Description: - * Routine called by the server-side callback RPC interface to - * implement getting the given data collection from the extended - * File Server statistics. - * - * Arguments: - * a_call : Ptr to Rx call on which this request came in. - * a_clientVersionNum : Client version number. - * a_opCode : Desired operation. - * a_serverVersionNumP : Ptr to version number to set. - * a_timeP : Ptr to time value (seconds) to set. - * a_dataP : Ptr to variable array structure to return - * stuff in. - * - * Returns: - * 0 (always). - * - * Environment: - * Nothing interesting. - * - * Side Effects: - * As advertised. - *------------------------------------------------------------------------*/ +Bad_Rename: + if (newfileptr) { + VPutVnode(&fileCode, newfileptr); + assert(fileCode == 0); + } + PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0), + oldvptr, volptr); + FidZap(&olddir); + FidZap(&newdir); + FidZap(&filedir); + FidZap(&newfiledir); + ViceLog(2, ("SAFS_Rename returns %d\n", errorCode)); + return errorCode; -afs_int32 SRXAFS_GetXStats(struct rx_call *a_call, - afs_int32 a_clientVersionNum, - afs_int32 a_collectionNumber, - afs_int32 *a_srvVersionNumP, - afs_int32 *a_timeP, - AFS_CollData *a_dataP) -{ /*SRXAFS_GetXStats*/ +} /*SAFSS_Rename*/ - register int code; /*Return value*/ - afs_int32 *dataBuffP; /*Ptr to data to be returned*/ - afs_int32 dataBytes; /*Bytes in data buffer*/ + +afs_int32 SRXAFS_Rename (struct rx_call *acall, + struct AFSFid *OldDirFid, + char *OldName, + struct AFSFid *NewDirFid, + char *NewName, + struct AFSFetchStatus *OutOldDirStatus, + struct AFSFetchStatus *OutNewDirStatus, + struct AFSVolSync *Sync) +{ + afs_int32 code; + struct rx_connection *tcon; #if FS_STATS_DETAILED struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ struct timeval opStartTime, @@ -4099,119 +4024,220 @@ afs_int32 SRXAFS_GetXStats(struct rx_call *a_call, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETXSTATS]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]); FS_LOCK (opP->numOps)++; FS_UNLOCK TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ - /* - * Record the time of day and the server version number. - */ - *a_srvVersionNumP = AFS_XSTAT_VERSION; - *a_timeP = FT_ApproxTime(); + if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_Rename; + + code = SAFSS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName, + OutOldDirStatus, OutNewDirStatus, Sync); + +Bad_Rename: + CallPostamble(tcon); + +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (code == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK + } + +#endif /* FS_STATS_DETAILED */ + + osi_auditU (acall, RenameFileEvent, code, AUD_FID, OldDirFid, AUD_STR, OldName, AUD_FID, NewDirFid, AUD_STR, NewName, AUD_END); + return code; + +} /*SRXAFS_Rename*/ + + +/* + * This routine is called exclusively by SRXAFS_Symlink(), and should be + * merged into it when possible. + */ +static afs_int32 +SAFSS_Symlink (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + char *LinkContents, + struct AFSStoreStatus *InStatus, + struct AFSFid *OutFid, + struct AFSFetchStatus *OutFidStatus, + struct AFSFetchStatus *OutDirStatus, + struct AFSVolSync *Sync) + +{ + Vnode * parentptr = 0; /* vnode of input Directory */ + Vnode * targetptr = 0; /* vnode of the new link */ + Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ + int errorCode = 0; /* error code */ + int 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 */ + afs_int32 rights, anyrights, fd; /* 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 */ + FdHandle_t *fdP; + struct rx_connection *tcon = rx_ConnectionOf(acall); + + FidZero(&dir); + + /* Get ptr to client data for user Id for logging */ + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); + ViceLog(1, ("SAFS_Symlink %s to %s, Did = %u.%d.%d, Host %s, Id %d\n", Name, + LinkContents, DirFid->Volume, DirFid->Vnode, DirFid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); + FS_LOCK + AFSCallStats.Symlink++, AFSCallStats.TotalCalls++; + FS_UNLOCK + if (!FileNameOK(Name)) { + errorCode = EINVAL; + goto Bad_SymLink; + } /* - * Stuff the appropriate data in there (assume victory) + * Get the vnode and volume for the parent dir along with the caller's + * rights to it */ - code = 0; + if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, + MustBeDIR, &parentwhentargetnotdir, + &client, WRITE_LOCK, &rights, &anyrights))) { + goto Bad_SymLink; + } - ViceLog(1, ("Received GetXStats call for collection %d\n", a_collectionNumber)); + /* set volume synchronization information */ + SetVolumeSync(Sync, volptr); + + /* Does the caller has insert (and write) access to the parent directory? */ + if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) { + goto Bad_SymLink; + } -#if 0 /* - * We're not keeping stats, so just return successfully with - * no data. + * If we're creating a mount point (any x bits clear), we must have + * administer access to the directory, too. Always allow sysadmins + * to do this. */ - a_dataP->AFS_CollData_len = 0; - a_dataP->AFS_CollData_val = NULL; -#endif /* 0 */ - - switch(a_collectionNumber) { - case AFS_XSTATSCOLL_CALL_INFO: - /* - * Pass back all the call-count-related data. - * - * >>> We are forced to allocate a separate area in which to - * >>> put this stuff in by the RPC stub generator, since it - * >>> will be freed at the tail end of the server stub code. - */ -#if 0 + if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) { + if (readonlyServer) { + errorCode = VREADONLY; + goto Bad_SymLink; + } /* - * I don't think call-level stats are being collected yet - * for the File Server. + * We have a mountpoint, 'cause we're trying to set the Unix mode + * bits to something with some x bits missing (default mode bits + * if AFS_SETMODE is false is 0777) */ - dataBytes = sizeof(struct afs_Stats); - dataBuffP = (afs_int32 *)malloc(dataBytes); - memcpy(dataBuffP, &afs_cmstats, dataBytes); - a_dataP->AFS_CollData_len = dataBytes>>2; - a_dataP->AFS_CollData_val = dataBuffP; + if (VanillaUser(client) && !(rights & PRSFS_ADMINISTER)) { + errorCode = EACCES; + goto Bad_SymLink; + } + } + + /* get a new vnode for the symlink and set it up */ + if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr, + Name, OutFid, vSymlink, + nBlocks(strlen((char *) LinkContents))))) { + goto Bad_SymLink; + } + + /* update the status of the parent vnode */ +#if FS_STATS_DETAILED + Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, + parentptr->disk.linkCount, client->InSameNetwork); #else - a_dataP->AFS_CollData_len = 0; - a_dataP->AFS_CollData_val = NULL; -#endif /* 0 */ - break; + Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, + parentptr->disk.linkCount); +#endif /* FS_STATS_DETAILED */ - case AFS_XSTATSCOLL_PERF_INFO: - /* - * Pass back all the regular performance-related data. - * - * >>> We are forced to allocate a separate area in which to - * >>> put this stuff in by the RPC stub generator, since it - * >>> will be freed at the tail end of the server stub code. - */ + /* update the status of the new symbolic link file vnode */ + Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus, parentptr, + volptr, strlen((char *)LinkContents)); - afs_perfstats.numPerfCalls++; - FillPerfValues(&afs_perfstats); + /* Write the contents of the symbolic link name into the target inode */ + fdP = IH_OPEN(targetptr->handle); + assert(fdP != NULL); + assert(FDH_WRITE(fdP, (char *) LinkContents, strlen((char *) LinkContents)) == strlen((char *) LinkContents)); + FDH_CLOSE(fdP); + /* + * Set up and return modified status for the parent dir and new symlink + * to caller. + */ + GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr); + GetStatus(parentptr, OutDirStatus, rights, anyrights, 0); - /* - * Don't overwrite the spares at the end. - */ + /* convert the write lock to a read lock before breaking callbacks */ + VVnodeWriteToRead(&errorCode, parentptr); + assert(!errorCode || errorCode == VSALVAGE); - dataBytes = sizeof(struct afs_PerfStats); - dataBuffP = (afs_int32 *)osi_Alloc(dataBytes); - memcpy(dataBuffP, &afs_perfstats, dataBytes); - a_dataP->AFS_CollData_len = dataBytes>>2; - a_dataP->AFS_CollData_val = dataBuffP; - break; + /* break call back on the parent dir */ + BreakCallBack(client->host, DirFid, 0); - case AFS_XSTATSCOLL_FULL_PERF_INFO: - /* - * Pass back the full collection of performance-related data. - * We have to stuff the basic, overall numbers in, but the - * detailed numbers are kept in the structure already. - * - * >>> We are forced to allocate a separate area in which to - * >>> put this stuff in by the RPC stub generator, since it - * >>> will be freed at the tail end of the server stub code. - */ +Bad_SymLink: + /* Write the all modified vnodes (parent, new files) and volume back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); + FidZap(&dir); + ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode)); + return errorCode; - afs_perfstats.numPerfCalls++; +} /*SAFSS_Symlink*/ + + +afs_int32 SRXAFS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync) + struct AFSVolSync *Sync; + struct rx_call *acall; /* Rx call */ + struct AFSFid *DirFid; /* Parent dir's fid */ + char *Name; /* File name to create */ + char *LinkContents; /* Contents of the new created file */ + struct AFSStoreStatus *InStatus; /* Input status for the new symbolic link */ + struct AFSFid *OutFid; /* Fid for newly created symbolic link */ + struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */ + struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */ + +{ + afs_int32 code; + struct rx_connection *tcon; #if FS_STATS_DETAILED - afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls; - FillPerfValues(&afs_FullPerfStats.overall); + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ + + /* + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. + */ + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ - /* - * Don't overwrite the spares at the end. - */ + if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_Symlink; - dataBytes = sizeof(struct fs_stats_FullPerfStats); - dataBuffP = (afs_int32 *)osi_Alloc(dataBytes); - memcpy(dataBuffP, &afs_FullPerfStats, dataBytes); - a_dataP->AFS_CollData_len = dataBytes>>2; - a_dataP->AFS_CollData_val = dataBuffP; -#endif - break; + code = SAFSS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, + OutFidStatus, OutDirStatus, Sync); - default: - /* - * Illegal collection number. - */ - a_dataP->AFS_CollData_len = 0; - a_dataP->AFS_CollData_val = NULL; - code = 1; - } /*Switch on collection number*/ +Bad_Symlink: + CallPostamble(tcon); #if FS_STATS_DETAILED TM_GetTimeOfDay(&opStopTime, 0); @@ -4232,18 +4258,159 @@ afs_int32 SRXAFS_GetXStats(struct rx_call *a_call, #endif /* FS_STATS_DETAILED */ - return(code); + osi_auditU (acall, SymlinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END); + return code; -} /*SRXAFS_GetXStats*/ +} /*SRXAFS_Symlink*/ -afs_int32 SRXAFS_GiveUpCallBacks (struct rx_call *acall, - struct AFSCBFids *FidArray, - struct AFSCBs *CallBackArray) +/* + * This routine is called exclusively by SRXAFS_Link(), and should be + * merged into it when possible. + */ +static afs_int32 +SAFSS_Link (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + struct AFSFid *ExistingFid, + struct AFSFetchStatus *OutFidStatus, + struct AFSFetchStatus *OutDirStatus, + struct AFSVolSync *Sync) { - afs_int32 errorCode; - register int i; - struct client *client; + Vnode * parentptr = 0; /* vnode of input Directory */ + Vnode * targetptr = 0; /* vnode of the new file */ + Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ + 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 */ + 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 */ + struct rx_connection *tcon = rx_ConnectionOf(acall); + + FidZero(&dir); + + /* Get ptr to client data for user Id for logging */ + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); + ViceLog(1, ("SAFS_Link %s, Did = %u.%d.%d, Fid = %u.%d.%d, Host %s, Id %d\n", + Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique, + ExistingFid->Volume, ExistingFid->Vnode, ExistingFid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); + FS_LOCK + AFSCallStats.Link++, AFSCallStats.TotalCalls++; + FS_UNLOCK + if (DirFid->Volume != ExistingFid->Volume) { + errorCode = EXDEV; + goto Bad_Link; + } + if (!FileNameOK(Name)) { + errorCode = EINVAL; + goto Bad_Link; + } + + /* + * Get the vnode and volume for the parent dir along with the caller's + * rights to it + */ + if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, + MustBeDIR, &parentwhentargetnotdir, + &client, WRITE_LOCK, &rights, &anyrights))) { + goto Bad_Link; + } + + /* set volume synchronization information */ + SetVolumeSync(Sync, volptr); + + /* Can the caller insert into the parent directory? */ + if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) { + goto Bad_Link; + } + + if (((DirFid->Vnode & 1) && (ExistingFid->Vnode & 1)) || + (DirFid->Vnode == ExistingFid->Vnode)) { /* at present, */ + /* AFS fileservers always have directory vnodes that are odd. */ + errorCode = EISDIR; + goto Bad_Link; + } + + /* get the file vnode */ + if ((errorCode = CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK))) { + goto Bad_Link; + } + if (targetptr->disk.type != vFile) { + errorCode = EISDIR; + goto Bad_Link; + } + if (targetptr->disk.parent != DirFid->Vnode) { + errorCode = EXDEV; + goto Bad_Link; + } + if (parentptr->disk.cloned) + { + ViceLog(25, ("Link : calling CopyOnWrite on target dir\n")); + if ( ( errorCode = CopyOnWrite(parentptr, volptr))) + goto Bad_Link; /* disk full error */ + } + + /* add the name to the directory */ + SetDirHandle(&dir, parentptr); + if ((errorCode = Create(&dir, (char *)Name, ExistingFid))) + goto Bad_Link; + DFlush(); + + /* update the status in the parent vnode */ + /**WARNING** --> disk.author SHOULDN'T be modified???? */ +#if FS_STATS_DETAILED + Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, + parentptr->disk.linkCount, client->InSameNetwork); +#else + Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, + parentptr->disk.linkCount); +#endif /* FS_STATS_DETAILED */ + + targetptr->disk.linkCount++; + targetptr->disk.author = client->ViceId; + targetptr->changed_newTime = 1; /* Status change of linked-to file */ + + /* set up return status */ + GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr); + GetStatus(parentptr, OutDirStatus, rights, anyrights, 0); + + /* convert the write locks to read locks before breaking callbacks */ + VVnodeWriteToRead(&errorCode, targetptr); + assert(!errorCode || errorCode == VSALVAGE); + VVnodeWriteToRead(&errorCode, parentptr); + assert(!errorCode || errorCode == VSALVAGE); + + /* break call back on DirFid */ + BreakCallBack(client->host, DirFid, 0); + /* + * We also need to break the callback for the file that is hard-linked since part + * of its status (like linkcount) is changed + */ + BreakCallBack(client->host, ExistingFid, 0); + +Bad_Link: + /* Write the all modified vnodes (parent, new files) and volume back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); + FidZap(&dir); + ViceLog(2, ("SAFS_Link returns %d\n", errorCode)); + return errorCode; + +} /*SAFSS_Link*/ + + +afs_int32 SRXAFS_Link (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + struct AFSFid *ExistingFid, + struct AFSFetchStatus *OutFidStatus, + struct AFSFetchStatus *OutDirStatus, + struct AFSVolSync *Sync) +{ + afs_int32 code; struct rx_connection *tcon; #if FS_STATS_DETAILED struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ @@ -4255,42 +4422,25 @@ afs_int32 SRXAFS_GiveUpCallBacks (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GIVEUPCALLBACKS]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]); FS_LOCK (opP->numOps)++; FS_UNLOCK TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ - ViceLog(1, ("SAFS_GiveUpCallBacks (Noffids=%d)\n", FidArray->AFSCBFids_len)); - FS_LOCK - AFSCallStats.GiveUpCallBacks++, AFSCallStats.TotalCalls++; - FS_UNLOCK - if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_GiveUpCallBacks; - - if (FidArray->AFSCBFids_len < CallBackArray->AFSCBs_len) { - ViceLog(0, ("GiveUpCallBacks: #Fids %d < #CallBacks %d, host=%x\n", - FidArray->AFSCBFids_len, CallBackArray->AFSCBs_len, - (tcon->peer ? tcon->peer->host : 0))); - errorCode = EINVAL; - goto Bad_GiveUpCallBacks; - } - - errorCode = GetClient(tcon, &client); - if (!errorCode) { - for (i=0; i < FidArray->AFSCBFids_len; i++) { - register struct AFSFid *fid = &(FidArray->AFSCBFids_val[i]); - DeleteCallBack(client->host, fid); - } - } + if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_Link; -Bad_GiveUpCallBacks: + code = SAFSS_Link (acall, DirFid, Name, ExistingFid, OutFidStatus, + OutDirStatus, Sync); + +Bad_Link: CallPostamble(tcon); #if FS_STATS_DETAILED TM_GetTimeOfDay(&opStopTime, 0); - if (errorCode == 0) { + if (code == 0) { FS_LOCK (opP->numSuccesses)++; fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); @@ -4304,232 +4454,316 @@ Bad_GiveUpCallBacks: } FS_UNLOCK } -#endif /* FS_STATS_DETAILED */ -out: - return errorCode; - -} /*SRXAFS_GiveUpCallBacks*/ - - -afs_int32 SRXAFS_NGetVolumeInfo (struct rx_call *acall, - char *avolid, - struct AFSVolumeInfo *avolinfo) -{ - return(VNOVOL); /* XXX Obsolete routine XXX */ -} /*SRXAFS_NGetVolumeInfo*/ - - -/* - * Dummy routine. Should never be called (the cache manager should only - * invoke this interface when communicating with a AFS/DFS Protocol - * Translator). - */ -afs_int32 SRXAFS_Lookup(struct rx_call *call_p, - struct AFSFid *afs_dfid_p, - char *afs_name_p, - struct AFSFid *afs_fid_p, - struct AFSFetchStatus *afs_status_p, - struct AFSFetchStatus *afs_dir_status_p, - struct AFSCallBack *afs_callback_p, - struct AFSVolSync *afs_sync_p) -{ - return EINVAL; -} +#endif /* FS_STATS_DETAILED */ + osi_auditU (acall, LinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_FID, ExistingFid, AUD_END); + return code; + +} /*SRXAFS_Link*/ + + +/* + * This routine is called exclusively by SRXAFS_MakeDir(), and should be + * merged into it when possible. + */ +static afs_int32 +SAFSS_MakeDir (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + struct AFSStoreStatus *InStatus, + struct AFSFid *OutFid, + struct AFSFetchStatus *OutFidStatus, + struct AFSFetchStatus *OutDirStatus, + struct AFSCallBack *CallBack, + struct AFSVolSync *Sync) -afs_int32 SRXAFS_FlushCPS(struct rx_call *acall, - struct ViceIds *vids, - struct IPAddrs *addrs, - afs_int32 spare1, - afs_int32 *spare2, - afs_int32 *spare3) { - int i; - afs_int32 nids, naddrs; - afs_int32 *vd, *addr; - int errorCode = 0; /* return code to caller */ - struct client *client; + Vnode * parentptr = 0; /* vnode of input Directory */ + Vnode * targetptr = 0; /* vnode of the new file */ + Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ + Volume * volptr = 0; /* pointer to the volume header */ + int errorCode = 0; /* error code */ + struct acl_accessList * newACL; /* Access list */ + 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 */ + 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 */ struct rx_connection *tcon = rx_ConnectionOf(acall); - ViceLog(1, ("SRXAFS_FlushCPS\n")); + FidZero(&dir); + FidZero(&parentdir); + + /* Get ptr to client data for user Id for logging */ + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); + ViceLog(1, ("SAFS_MakeDir %s, Did = %u.%d.%d, Host %s, Id %d\n", + Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); FS_LOCK - AFSCallStats.TotalCalls++; + AFSCallStats.MakeDir++, AFSCallStats.TotalCalls++; FS_UNLOCK - nids = vids->ViceIds_len; /* # of users in here */ - naddrs = addrs->IPAddrs_len; /* # of hosts in here */ - if (nids < 0 || naddrs < 0) { + if (!FileNameOK(Name)) { errorCode = EINVAL; - goto Bad_FlushCPS; + goto Bad_MakeDir; } - vd = vids->ViceIds_val; - for (i=0; ilock); - client->prfail = 2; /* Means re-eval client's cps */ -#ifdef notdef - if (client->tcon) { - rx_SetRock(((struct rx_connection *) client->tcon), 0); - } -#endif - if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) { - free(client->CPS.prlist_val); - client->CPS.prlist_val = NULL; - } - ReleaseWriteLock(&client->lock); + /* Write access to the parent directory? */ +#ifdef DIRCREATE_NEED_WRITE + /* + * requires w access for the user to create a directory. this + * closes a loophole in the current security arrangement, since a + * user with i access only can create a directory and get the + * implcit a access that goes with dir ownership, and proceed to + * subvert quota in the volume. + */ + if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) || + (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) { +#else + if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) { +#endif /* DIRCREATE_NEED_WRITE */ + goto Bad_MakeDir; } - addr = addrs->IPAddrs_val; - for (i=0; iViceId, + parentptr->disk.linkCount+1, client->InSameNetwork); +#else + Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId, + parentptr->disk.linkCount+1); +#endif /* FS_STATS_DETAILED */ + + /* Point to target's ACL buffer and copy the parent's ACL contents to it */ + assert((SetAccessList(&targetptr, &volptr, &newACL, &newACLSize, + &parentwhentargetnotdir, (AFSFid *)0, 0)) == 0); + assert(parentwhentargetnotdir == 0); + memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr)); + + /* update the status for the target vnode */ + Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus, + parentptr, volptr, 0); + + /* Actually create the New directory in the directory package */ + SetDirHandle(&dir, targetptr); + assert(!(MakeDir(&dir, OutFid, DirFid))); + DFlush(); + targetptr->disk.length = Length(&dir); + + /* set up return status */ + GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr); + GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL); + + /* convert the write lock to a read lock before breaking callbacks */ + VVnodeWriteToRead(&errorCode, parentptr); + assert(!errorCode || errorCode == VSALVAGE); + + /* break call back on DirFid */ + BreakCallBack(client->host, DirFid, 0); + + /* Return a callback promise to caller */ + SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack); + +Bad_MakeDir: + /* Write the all modified vnodes (parent, new files) and volume back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); + FidZap(&dir); + FidZap(&parentdir); + ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode)); return errorCode; -} /*SRXAFS_FlushCPS */ -/* worthless hack to let CS keep running ancient software */ -static int afs_vtoi(register char *aname) -{ - register afs_int32 temp; - register int tc; +} /*SAFSS_MakeDir*/ - temp = 0; - while((tc = *aname++)) { - if (tc > '9' || tc < '0') return 0; /* invalid name */ - temp *= 10; - temp += tc - '0'; - } - return temp; -} -/* - * may get name or #, but must handle all weird cases (recognize readonly - * or backup volumes by name or # - */ -static afs_int32 CopyVolumeEntry(char *aname,register struct vldbentry *ave, - register struct VolumeInfo *av) +afs_int32 SRXAFS_MakeDir (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + struct AFSStoreStatus *InStatus, + struct AFSFid *OutFid, + struct AFSFetchStatus *OutFidStatus, + struct AFSFetchStatus *OutDirStatus, + struct AFSCallBack *CallBack, + struct AFSVolSync *Sync) { - register int i, j, vol; - afs_int32 mask, whichType; - afs_uint32 *serverHost, *typePtr; - - /* figure out what type we want if by name */ - i = strlen(aname); - if (i >= 8 && strcmp(aname+i-7, ".backup") == 0) - whichType = BACKVOL; - else if (i >= 10 && strcmp(aname+i-9, ".readonly")==0) - whichType = ROVOL; - else whichType = RWVOL; - - vol = afs_vtoi(aname); - if (vol == 0) vol = ave->volumeId[whichType]; - + afs_int32 code; + struct rx_connection *tcon; +#if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ + /* - * Now vol has volume # we're interested in. Next, figure out the type - * of the volume by looking finding it in the vldb entry + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. */ - if ((ave->flags&VLF_RWEXISTS) && vol == ave->volumeId[RWVOL]) { - mask = VLSF_RWVOL; - whichType = RWVOL; - } - else if ((ave->flags&VLF_ROEXISTS) && vol == ave->volumeId[ROVOL]) { - mask = VLSF_ROVOL; - whichType = ROVOL; - } - else if ((ave->flags&VLF_BACKEXISTS) && vol == ave->volumeId[BACKVOL]) { - mask = VLSF_RWVOL; /* backup always is on the same volume as parent */ - whichType = BACKVOL; - } - else - return EINVAL; /* error: can't find volume in vldb entry */ - - typePtr = &av->Type0; - serverHost = &av->Server0; - av->Vid = vol; - av->Type = whichType; - av->Type0 = av->Type1 = av->Type2 = av->Type3 = av->Type4 = 0; - if (ave->flags & VLF_RWEXISTS) typePtr[RWVOL] = ave->volumeId[RWVOL]; - if (ave->flags & VLF_ROEXISTS) typePtr[ROVOL] = ave->volumeId[ROVOL]; - if (ave->flags & VLF_BACKEXISTS) typePtr[BACKVOL] = ave->volumeId[BACKVOL]; - - for(i=0,j=0; inServers; i++) { - if ((ave->serverFlags[i] & mask) == 0) continue; /* wrong volume */ - serverHost[j] = ave->serverNumber[i]; - j++; - } - av->ServerCount = j; - if (j < 8) serverHost[j++] = 0; /* bogus 8, but compat only now */ - return 0; -} + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ + if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_MakeDir; -static afs_int32 TryLocalVLServer(char *avolid, struct VolumeInfo *avolinfo) -{ - static struct rx_connection *vlConn = 0; - static int down = 0; - static afs_int32 lastDownTime = 0; - struct vldbentry tve; - struct rx_securityClass *vlSec; - register afs_int32 code; + code = SAFSS_MakeDir (acall, DirFid, Name, InStatus, OutFid, + OutFidStatus, OutDirStatus, CallBack, Sync); + +Bad_MakeDir: + CallPostamble(tcon); - if (!vlConn) { - vlSec = rxnull_NewClientSecurityObject(); - vlConn = rx_NewConnection(htonl(0x7f000001), htons(7003), 52, vlSec, 0); - rx_SetConnDeadTime(vlConn, 15); /* don't wait long */ - } - if (down && (FT_ApproxTime() < lastDownTime + 180)) { - return 1; /* failure */ +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (code == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK } - code = VL_GetEntryByNameO(vlConn, avolid, &tve); - if (code >= 0) down = 0; /* call worked */ - if (code) { - if (code < 0) { - lastDownTime = FT_ApproxTime(); /* last time we tried an RPC */ - down = 1; - } - return code; - } +#endif /* FS_STATS_DETAILED */ - /* otherwise convert to old format vldb entry */ - code = CopyVolumeEntry(avolid, &tve, avolinfo); + osi_auditU (acall, MakeDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END); return code; -} +} /*SRXAFS_MakeDir*/ + + +/* + * This routine is called exclusively by SRXAFS_RemoveDir(), and should be + * merged into it when possible. + */ static afs_int32 -GetVolumeInfo (struct rx_call *acall, - char *avolid, - struct VolumeInfo *avolinfo) +SAFSS_RemoveDir (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + struct AFSFetchStatus *OutDirStatus, + struct AFSVolSync *Sync) + { - int errorCode = 0; /* error code */ + Vnode * parentptr = 0; /* vnode of input Directory */ + Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ + Vnode * targetptr = 0; /* file to be deleted */ + AFSFid fileFid; /* area for Fid from the directory */ + 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 */ + afs_int32 rights, anyrights; /* rights for this and any user */ + Vnode debugvnode1, debugvnode2; + struct client *t_client; /* tmp ptr to client data */ + struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ + struct rx_connection *tcon = rx_ConnectionOf(acall); + + FidZero(&dir); + /* Get ptr to client data for user Id for logging */ + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); + ViceLog(1, ("SAFS_RemoveDir %s, Did = %u.%d.%d, Host %s, Id %d\n", + Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); FS_LOCK - AFSCallStats.GetVolumeInfo++, AFSCallStats.TotalCalls++; + AFSCallStats.RemoveDir++, AFSCallStats.TotalCalls++; FS_UNLOCK + /* + * Get the vnode and volume for the parent dir along with the caller's + * rights to it + */ + if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr, + MustBeDIR, &parentwhentargetnotdir, + &client, WRITE_LOCK, &rights, &anyrights))) { + goto Bad_RemoveDir; + } + debugvnode1 = *parentptr; - errorCode = TryLocalVLServer(avolid, avolinfo); - ViceLog(1, ("SAFS_GetVolumeInfo returns %d, Volume %u, type %x, servers %x %x %x %x...\n", - errorCode, avolinfo->Vid, avolinfo->Type, - avolinfo->Server0, avolinfo->Server1, avolinfo->Server2, - avolinfo->Server3)); - return(errorCode); -} + /* set volume synchronization information */ + SetVolumeSync(Sync, volptr); + /* Does the caller has delete (&write) access to the parent dir? */ + if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) { + goto Bad_RemoveDir; + } + debugvnode2 = *parentptr; + /* Do the actual delete of the desired (empty) directory, Name */ + if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid, + Name, MustBeDIR))) { + goto Bad_RemoveDir; + } + /* Update the status for the parent dir; link count is also adjusted */ +#if FS_STATS_DETAILED + Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, + parentptr->disk.linkCount-1, client->InSameNetwork); +#else + Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId, + parentptr->disk.linkCount-1); +#endif /* FS_STATS_DETAILED */ + /* Return to the caller the updated parent dir status */ + GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL); -afs_int32 SRXAFS_GetVolumeInfo (struct rx_call *acall, - char *avolid, - struct VolumeInfo *avolinfo) + /* + * Note: it is not necessary to break the callback on fileFid, since + * refcount is now 0, so no one should be able to refer to the dir + * any longer + */ + DeleteFileCallBacks(&fileFid); + + /* convert the write lock to a read lock before breaking callbacks */ + VVnodeWriteToRead(&errorCode, parentptr); + assert(!errorCode || errorCode == VSALVAGE); + + /* break call back on DirFid and fileFid */ + BreakCallBack(client->host, DirFid, 0); + +Bad_RemoveDir: + /* Write the all modified vnodes (parent, new files) and volume back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); + FidZap(&dir); + ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode)); + return errorCode; + +} /*SAFSS_RemoveDir*/ + + +afs_int32 SRXAFS_RemoveDir (struct rx_call *acall, + struct AFSFid *DirFid, + char *Name, + struct AFSFetchStatus *OutDirStatus, + struct AFSVolSync *Sync) { afs_int32 code; struct rx_connection *tcon; @@ -4543,19 +4777,19 @@ afs_int32 SRXAFS_GetVolumeInfo (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMEINFO]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]); FS_LOCK (opP->numOps)++; FS_UNLOCK TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ - if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_GetVolumeInfo; - code = GetVolumeInfo (tcon, avolid, avolinfo); - avolinfo->Type4 = 0xabcd9999; /* tell us to try new vldb */ + if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_RemoveDir; -Bad_GetVolumeInfo: + code = SAFSS_RemoveDir (acall, DirFid, Name, OutDirStatus, Sync); + +Bad_RemoveDir: CallPostamble(tcon); #if FS_STATS_DETAILED @@ -4577,25 +4811,92 @@ Bad_GetVolumeInfo: #endif /* FS_STATS_DETAILED */ + osi_auditU (acall, RemoveDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END); return code; -} /*SRXAFS_GetVolumeInfo*/ +} /*SRXAFS_RemoveDir*/ -afs_int32 SRXAFS_GetVolumeStatus(struct rx_call *acall, - afs_int32 avolid, - AFSFetchVolumeStatus *FetchVolStatus, - char **Name, - char **OfflineMsg, - char **Motd) +/* + * This routine is called exclusively by SRXAFS_SetLock(), and should be + * merged into it when possible. + */ +static afs_int32 +SAFSS_SetLock (struct rx_call *acall, + struct AFSFid *Fid, + ViceLockType type, + struct AFSVolSync *Sync) +{ + Vnode * targetptr = 0; /* vnode of input file */ + 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 */ + 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 */ + static char * locktype[2] = {"LockRead","LockWrite"}; + struct rx_connection *tcon = rx_ConnectionOf(acall); + + if (type != LockRead && type != LockWrite) { + errorCode = EINVAL; + goto Bad_SetLock; + } + /* Get ptr to client data for user Id for logging */ + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); + ViceLog(1,("SAFS_SetLock type = %s Fid = %u.%d.%d, Host %s, Id %d\n", + locktype[(int)type], Fid->Volume, Fid->Vnode, Fid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); + FS_LOCK + AFSCallStats.SetLock++, AFSCallStats.TotalCalls++; + FS_UNLOCK + + /* + * Get the vnode and volume for the desired file along with the caller's + * rights to it + */ + if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, + DONTCHECK, &parentwhentargetnotdir, + &client, WRITE_LOCK, &rights, &anyrights))) { + goto Bad_SetLock; + } + + /* set volume synchronization information */ + SetVolumeSync(Sync, volptr); + + /* Handle the particular type of set locking, type */ + errorCode = HandleLocking(targetptr, rights, type); + +Bad_SetLock: + /* Write the all modified vnodes (parent, new files) and volume back */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + + if ((errorCode == VREADONLY) && (type == LockRead)) + errorCode = 0; /* allow read locks on RO volumes without saving state */ + + ViceLog(2,("SAFS_SetLock returns %d\n", errorCode)); + return(errorCode); + +} /*SAFSS_SetLock*/ + + +afs_int32 SRXAFS_OldSetLock(struct rx_call *acall, + struct AFSFid *Fid, + ViceLockType type, + struct AFSVolSync *Sync) +{ + return SRXAFS_SetLock(acall, Fid, type, Sync); + +} /*SRXAFS_OldSetLock*/ + + +afs_int32 SRXAFS_SetLock (struct rx_call *acall, + struct AFSFid *Fid, + ViceLockType type, + struct AFSVolSync *Sync) { - Vnode * targetptr = 0; /* vnode of the new file */ - 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 */ - afs_int32 rights, anyrights; /* rights for this and any user */ - AFSFid dummyFid; + afs_int32 code; struct rx_connection *tcon; #if FS_STATS_DETAILED struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ @@ -4607,50 +4908,24 @@ afs_int32 SRXAFS_GetVolumeStatus(struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMESTATUS]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]); FS_LOCK (opP->numOps)++; FS_UNLOCK TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ - ViceLog(1,("SAFS_GetVolumeStatus for volume %u\n", avolid)); - if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_GetVolumeStatus; - - FS_LOCK - AFSCallStats.GetVolumeStatus++, AFSCallStats.TotalCalls++; - FS_UNLOCK - - if (avolid == 0) { - errorCode = EINVAL; - goto Bad_GetVolumeStatus; - } - dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1; - - if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr, - MustBeDIR, &parentwhentargetnotdir, - &client, READ_LOCK, &rights, &anyrights))) - goto Bad_GetVolumeStatus; - - if ((VanillaUser(client)) && (!(rights & PRSFS_READ))) { - errorCode = EACCES; - goto Bad_GetVolumeStatus; - } - RXGetVolumeStatus(FetchVolStatus, Name, OfflineMsg, Motd, volptr); + if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_SetLock; -Bad_GetVolumeStatus: - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - ViceLog(2,("SAFS_GetVolumeStatus returns %d\n",errorCode)); - /* next is to guarantee out strings exist for stub */ - if (*Name == 0) {*Name = (char *) malloc(1); **Name = 0;} - if (*Motd == 0) {*Motd = (char *) malloc(1); **Motd = 0;} - if (*OfflineMsg == 0) {*OfflineMsg = (char *) malloc(1); **OfflineMsg = 0;} + code = SAFSS_SetLock (acall, Fid, type, Sync); + +Bad_SetLock: CallPostamble(tcon); #if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (errorCode == 0) { + TM_GetTimeOfDay(&opStopTime, 0); + if (code == 0) { FS_LOCK (opP->numSuccesses)++; fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); @@ -4664,28 +4939,87 @@ Bad_GetVolumeStatus: } FS_UNLOCK } - #endif /* FS_STATS_DETAILED */ - return(errorCode); -} /*SRXAFS_GetVolumeStatus*/ + osi_auditU (acall, SetLockEvent, code, AUD_FID, Fid, AUD_LONG, type, AUD_END); + return code; + +} /*SRXAFS_SetLock*/ -afs_int32 SRXAFS_SetVolumeStatus (struct rx_call *acall, - afs_int32 avolid, - AFSStoreVolumeStatus *StoreVolStatus, - char *Name, - char *OfflineMsg, - char *Motd) +/* + * This routine is called exclusively by SRXAFS_ExtendLock(), and should be + * merged into it when possible. + */ +static afs_int32 +SAFSS_ExtendLock (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSVolSync *Sync) + { - Vnode * targetptr = 0; /* vnode of the new file */ - Vnode * parentwhentargetnotdir = 0; /* vnode of parent */ + Vnode * targetptr = 0; /* vnode of input file */ + 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 entry */ + struct client * client; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ - AFSFid dummyFid; + struct client *t_client; /* tmp ptr to client data */ + struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ struct rx_connection *tcon = rx_ConnectionOf(acall); + + /* Get ptr to client data for user Id for logging */ + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); + ViceLog(1,("SAFS_ExtendLock Fid = %u.%d.%d, Host %s, Id %d\n", + Fid->Volume, Fid->Vnode, Fid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); + FS_LOCK + AFSCallStats.ExtendLock++, AFSCallStats.TotalCalls++; + FS_UNLOCK + /* + * Get the vnode and volume for the desired file along with the caller's + * rights to it + */ + if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, + DONTCHECK, &parentwhentargetnotdir, + &client, WRITE_LOCK, &rights, &anyrights))) { + goto Bad_ExtendLock; + } + + /* set volume synchronization information */ + SetVolumeSync(Sync, volptr); + + /* Handle the actual lock extension */ + errorCode = HandleLocking(targetptr, rights, LockExtend); + +Bad_ExtendLock: + /* Put back file's vnode and volume */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + + if ((errorCode == VREADONLY)) /* presumably, we already granted this lock */ + errorCode = 0; /* under our generous policy re RO vols */ + + ViceLog(2,("SAFS_ExtendLock returns %d\n", errorCode)); + return(errorCode); + +} /*SAFSS_ExtendLock*/ + + +afs_int32 SRXAFS_OldExtendLock (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSVolSync *Sync) +{ + return SRXAFS_ExtendLock(acall, Fid, Sync); + +} /*SRXAFS_OldExtendLock*/ + + +afs_int32 SRXAFS_ExtendLock (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSVolSync *Sync) +{ + afs_int32 code; + struct rx_connection *tcon; #if FS_STATS_DETAILED struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ struct timeval opStartTime, @@ -4696,52 +5030,24 @@ afs_int32 SRXAFS_SetVolumeStatus (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETVOLUMESTATUS]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_EXTENDLOCK]); FS_LOCK (opP->numOps)++; FS_UNLOCK TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ - ViceLog(1,("SAFS_SetVolumeStatus for volume %u\n", avolid)); - if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_SetVolumeStatus; - - FS_LOCK - AFSCallStats.SetVolumeStatus++, AFSCallStats.TotalCalls++; - FS_UNLOCK - - if (avolid == 0) { - errorCode = EINVAL; - goto Bad_SetVolumeStatus; - } - dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1; - - if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr, - MustBeDIR, &parentwhentargetnotdir, - &client, READ_LOCK, &rights, &anyrights))) - goto Bad_SetVolumeStatus; - - if (readonlyServer) { - errorCode = VREADONLY; - goto Bad_SetVolumeStatus; - } - if (VanillaUser(client)) { - errorCode = EACCES; - goto Bad_SetVolumeStatus; - } + if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_ExtendLock; - errorCode = RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name, - OfflineMsg, Motd); + code = SAFSS_ExtendLock (acall, Fid, Sync); - Bad_SetVolumeStatus: - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); - ViceLog(2,("SAFS_SetVolumeStatus returns %d\n",errorCode)); +Bad_ExtendLock: CallPostamble(tcon); #if FS_STATS_DETAILED TM_GetTimeOfDay(&opStopTime, 0); - if (errorCode == 0) { + if (code == 0) { FS_LOCK (opP->numSuccesses)++; fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); @@ -4758,99 +5064,91 @@ afs_int32 SRXAFS_SetVolumeStatus (struct rx_call *acall, #endif /* FS_STATS_DETAILED */ - osi_auditU (acall, SetVolumeStatusEvent, errorCode, AUD_LONG, avolid, AUD_STR, Name, AUD_END); - return(errorCode); - -} /*SRXAFS_SetVolumeStatus*/ + osi_auditU (acall, ExtendLockEvent, code, AUD_FID, Fid , AUD_END); + return code; -#define DEFAULTVOLUME "root.afs" +} /*SRXAFS_ExtendLock*/ -afs_int32 SRXAFS_GetRootVolume (struct rx_call *acall, char **VolumeName) -{ - int fd; - int len; - char *temp; - int errorCode = 0; /* error code */ - struct rx_connection *tcon; -#if FS_STATS_DETAILED - struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ - struct timeval opStartTime, - opStopTime; /* Start/stop times for RPC op*/ - struct timeval elapsedTime; /* Transfer time */ - /* - * Set our stats pointer, remember when the RPC operation started, and - * tally the operation. - */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETROOTVOLUME]); - FS_LOCK - (opP->numOps)++; - FS_UNLOCK - TM_GetTimeOfDay(&opStartTime, 0); -#endif /* FS_STATS_DETAILED */ +/* + * This routine is called exclusively by SRXAFS_ReleaseLock(), and should be + * merged into it when possible. + */ +static afs_int32 +SAFSS_ReleaseLock (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSVolSync *Sync) - return FSERR_EOPNOTSUPP; +{ + Vnode * targetptr = 0; /* vnode of input file */ + 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 */ + 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 */ + struct rx_connection *tcon = rx_ConnectionOf(acall); -#ifdef notdef - if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon)) - goto Bad_GetRootVolume; + /* Get ptr to client data for user Id for logging */ + t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(tcon)); + ViceLog(1,("SAFS_ReleaseLock Fid = %u.%d.%d, Host %s, Id %d\n", + Fid->Volume, Fid->Vnode, Fid->Unique, + inet_ntoa(logHostAddr), t_client->ViceId)); FS_LOCK - AFSCallStats.GetRootVolume++, AFSCallStats.TotalCalls++; - FS_UNLOCK - - temp = malloc(256); - fd = open(AFSDIR_SERVER_ROOTVOL_FILEPATH, O_RDONLY, 0666); - if (fd <= 0) - strcpy(temp, DEFAULTVOLUME); - else { -#if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV) - lockf(fd, F_LOCK, 0); -#else - flock(fd, LOCK_EX); -#endif - len = read(fd, temp, 256); -#if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV) - lockf(fd, F_ULOCK, 0); -#else - flock(fd, LOCK_UN); -#endif - close(fd); - if (temp[len-1] == '\n') len--; - temp[len] = '\0'; + AFSCallStats.ReleaseLock++, AFSCallStats.TotalCalls++; + FS_UNLOCK + /* + * Get the vnode and volume for the desired file along with the caller's + * rights to it + */ + if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr, + DONTCHECK, &parentwhentargetnotdir, + &client, WRITE_LOCK, &rights, &anyrights))) { + goto Bad_ReleaseLock; } - *VolumeName = temp; /* freed by rx server-side stub */ -Bad_GetRootVolume: - CallPostamble(tcon); + /* set volume synchronization information */ + SetVolumeSync(Sync, volptr); -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - if (errorCode == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK + /* Handle the actual lock release */ + if ((errorCode = HandleLocking(targetptr, rights, LockRelease))) + goto Bad_ReleaseLock; + + /* if no more locks left, a callback would be triggered here */ + if (targetptr->disk.lock.lockCount <= 0) { + /* convert the write lock to a read lock before breaking callbacks */ + VVnodeWriteToRead(&errorCode, targetptr); + assert(!errorCode || errorCode == VSALVAGE); + BreakCallBack(client->host, Fid, 0); } -#endif /* FS_STATS_DETAILED */ +Bad_ReleaseLock: + /* Put back file's vnode and volume */ + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + + if ((errorCode == VREADONLY)) /* presumably, we already granted this lock */ + errorCode = 0; /* under our generous policy re RO vols */ + + ViceLog(2,("SAFS_ReleaseLock returns %d\n", errorCode)); return(errorCode); -#endif /* notdef */ -} /*SRXAFS_GetRootVolume*/ +} /*SAFSS_ReleaseLock*/ -/* still works because a struct CBS is the same as a struct AFSOpaque */ -afs_int32 SRXAFS_CheckToken (struct rx_call *acall, - afs_int32 AfsId, - struct AFSOpaque *Token) +afs_int32 SRXAFS_OldReleaseLock (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSVolSync *Sync) +{ + return SRXAFS_ReleaseLock(acall, Fid, Sync); + +} /*SRXAFS_OldReleaseLock*/ + + +afs_int32 SRXAFS_ReleaseLock (struct rx_call *acall, + struct AFSFid *Fid, + struct AFSVolSync *Sync) { afs_int32 code; struct rx_connection *tcon; @@ -4864,7 +5162,7 @@ afs_int32 SRXAFS_CheckToken (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CHECKTOKEN]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RELEASELOCK]); FS_LOCK (opP->numOps)++; FS_UNLOCK @@ -4872,11 +5170,11 @@ afs_int32 SRXAFS_CheckToken (struct rx_call *acall, #endif /* FS_STATS_DETAILED */ if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) - goto Bad_CheckToken; + goto Bad_ReleaseLock; - code = FSERR_ECONNREFUSED; + code = SAFSS_ReleaseLock (acall, Fid, Sync); -Bad_CheckToken: +Bad_ReleaseLock: CallPostamble(tcon); #if FS_STATS_DETAILED @@ -4898,17 +5196,82 @@ Bad_CheckToken: #endif /* FS_STATS_DETAILED */ + osi_auditU (acall, ReleaseLockEvent, code, AUD_FID, Fid , AUD_END); return code; -} /*SRXAFS_CheckToken*/ +} /*SRXAFS_ReleaseLock*/ -afs_int32 SRXAFS_GetTime (struct rx_call *acall, - afs_uint32 *Seconds, - afs_uint32 *USeconds) + +void SetSystemStats(struct AFSStatistics *stats) +{ + /* Fix this sometime soon.. */ + /* Because hey, it's not like we have a network monitoring protocol... */ + struct timeval time; + + /* this works on all system types */ + TM_GetTimeOfDay(&time, 0); + stats->CurrentTime = time.tv_sec; +} /*SetSystemStats*/ + +void SetAFSStats(struct AFSStatistics *stats) +{ + extern afs_int32 StartTime, CurrentConnections; + int seconds; + + FS_LOCK + stats->CurrentMsgNumber = 0; + stats->OldestMsgNumber = 0; + stats->StartTime = StartTime; + stats->CurrentConnections = CurrentConnections; + stats->TotalAFSCalls = AFSCallStats.TotalCalls; + stats->TotalFetchs = AFSCallStats.FetchData+AFSCallStats.FetchACL+AFSCallStats.FetchStatus; + stats->FetchDatas = AFSCallStats.FetchData; + stats->FetchedBytes = AFSCallStats.TotalFetchedBytes; + seconds = AFSCallStats.AccumFetchTime/1000; + if (seconds <= 0) seconds = 1; + stats->FetchDataRate = AFSCallStats.TotalFetchedBytes/seconds; + stats->TotalStores = AFSCallStats.StoreData+AFSCallStats.StoreACL+AFSCallStats.StoreStatus; + stats->StoreDatas = AFSCallStats.StoreData; + stats->StoredBytes = AFSCallStats.TotalStoredBytes; + seconds = AFSCallStats.AccumStoreTime/1000; + if (seconds <= 0) seconds = 1; + stats->StoreDataRate = AFSCallStats.TotalStoredBytes/seconds; +#ifdef AFS_NT40_ENV + stats->ProcessSize = -1; /* TODO: */ +#else + stats->ProcessSize = (afs_int32)((long) sbrk(0) >> 10); +#endif + FS_UNLOCK + h_GetWorkStats((int *)&(stats->WorkStations),(int *)&(stats->ActiveWorkStations), + (int *)0, (afs_int32)(FT_ApproxTime())-(15*60)); + +} /*SetAFSStats*/ + +/* Get disk related information from all AFS partitions. */ + +void SetVolumeStats(struct AFSStatistics *stats) +{ + struct DiskPartition * part; + int i = 0; + + for (part = DiskPartitionList; part && i < AFS_MSTATDISKS; part = part->next) { + stats->Disks[i].TotalBlocks = part->totalUsable; + stats->Disks[i].BlocksAvailable = part->free; + memset(stats->Disks[i].Name, 0, AFS_DISKNAMESIZE); + strncpy(stats->Disks[i].Name, part->name, AFS_DISKNAMESIZE); + i++; + } + while (i < AFS_MSTATDISKS) { + stats->Disks[i].TotalBlocks = -1; + i++; + } +} /*SetVolumeStats*/ + +afs_int32 SRXAFS_GetStatistics (struct rx_call *acall, + struct ViceStatistics *Statistics) { afs_int32 code; struct rx_connection *tcon; - struct timeval tpl; #if FS_STATS_DETAILED struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ struct timeval opStartTime, @@ -4919,7 +5282,7 @@ afs_int32 SRXAFS_GetTime (struct rx_call *acall, * Set our stats pointer, remember when the RPC operation started, and * tally the operation. */ - opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETTIME]); + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]); FS_LOCK (opP->numOps)++; FS_UNLOCK @@ -4927,1997 +5290,1619 @@ afs_int32 SRXAFS_GetTime (struct rx_call *acall, #endif /* FS_STATS_DETAILED */ if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon))) - goto Bad_GetTime; + goto Bad_GetStatistics; + ViceLog(1, ("SAFS_GetStatistics Received\n")); FS_LOCK - AFSCallStats.GetTime++, AFSCallStats.TotalCalls++; + AFSCallStats.GetStatistics++, AFSCallStats.TotalCalls++; FS_UNLOCK - - TM_GetTimeOfDay(&tpl, 0); - *Seconds = tpl.tv_sec; - *USeconds = tpl.tv_usec; - - ViceLog(2, ("SAFS_GetTime returns %d, %d\n", *Seconds, *USeconds)); + memset(Statistics, 0, sizeof(*Statistics)); + SetAFSStats((struct AFSStatistics *)Statistics); + SetVolumeStats((struct AFSStatistics *)Statistics); + SetSystemStats((struct AFSStatistics *)Statistics); -Bad_GetTime: +Bad_GetStatistics: CallPostamble(tcon); -#if FS_STATS_DETAILED - TM_GetTimeOfDay(&opStopTime, 0); - fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); - if (code == 0) { - FS_LOCK - (opP->numSuccesses)++; - fs_stats_AddTo((opP->sumTime), elapsedTime); - fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); - if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { - fs_stats_TimeAssign((opP->minTime), elapsedTime); - } - if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { - fs_stats_TimeAssign((opP->maxTime), elapsedTime); - } - FS_UNLOCK - } - -#endif /* FS_STATS_DETAILED */ - - return code; - -} /*SRXAFS_GetTime*/ - - -/* - * This unusual afs_int32-parameter routine encapsulates all volume package related - * operations together in a single function; it's called by almost all AFS - * interface calls. - */ -static afs_int32 -GetVolumePackage(struct rx_connection *tcon, - AFSFid *Fid, - Volume **volptr, - Vnode **targetptr, - int chkforDir, - Vnode **parent, - struct client **client, - int locktype, - afs_int32 *rights, - afs_int32 *anyrights) -{ - struct acl_accessList * aCL; /* Internal access List */ - int aCLSize; /* size of the access list */ - int errorCode = 0; /* return code to caller */ - - if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype))) - return(errorCode); - if (chkforDir) { - if (chkforDir == MustNOTBeDIR && ((*targetptr)->disk.type == vDirectory)) - return(EISDIR); - else if (chkforDir == MustBeDIR && ((*targetptr)->disk.type != vDirectory)) - return(ENOTDIR); - } - if ((errorCode = SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent, (chkforDir == MustBeDIR ? (AFSFid *)0 : Fid), (chkforDir == MustBeDIR ? 0 : locktype))) != 0) - 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); - /* 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 */ - if ((*targetptr)->disk.owner == (*client)->ViceId) - (*rights) |= PRSFS_ADMINISTER; - else - (*rights) &= ~PRSFS_ADMINISTER; - } -#ifdef ADMIN_IMPLICIT_LOOKUP - /* admins get automatic lookup on everything */ - if (!VanillaUser(*client)) (*rights) |= PRSFS_LOOKUP; -#endif /* ADMIN_IMPLICIT_LOOKUP */ - return errorCode; - -} /*GetVolumePackage*/ - - -/* - * This is the opposite of GetVolumePackage(), and is always used at the end of - * AFS calls to put back all used vnodes and the volume in the proper order! - */ -static afs_int32 -PutVolumePackage(Vnode *parentwhentargetnotdir, - Vnode *targetptr, - Vnode *parentptr, - Volume *volptr) -{ - int fileCode = 0; /* Error code returned by the volume package */ - - if (parentwhentargetnotdir) { - VPutVnode(&fileCode, parentwhentargetnotdir); - assert(!fileCode || (fileCode == VSALVAGE)); - } - if (targetptr) { - VPutVnode(&fileCode, targetptr); - assert(!fileCode || (fileCode == VSALVAGE)); - } - if (parentptr) { - VPutVnode(&fileCode, parentptr); - assert(!fileCode || (fileCode == VSALVAGE)); - } - if (volptr) { - VPutVolume(volptr); +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (code == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK } -} /*PutVolumePackage*/ +#endif /* FS_STATS_DETAILED */ + + return code; +} /*SRXAFS_GetStatistics*/ -/* - * FetchData_RXStyle + +/*------------------------------------------------------------------------ + * EXPORTED SRXAFS_XStatsVersion * - * Purpose: - * Implement a client's data fetch using Rx. + * Description: + * Routine called by the server-side RPC interface to implement + * pulling out the xstat version number for the File Server. * * Arguments: - * volptr : Ptr to the given volume's info. - * targetptr : Pointer to the vnode involved. - * Call : Ptr to the Rx call involved. - * Pos : Offset within the file. - * Len : Length in bytes to read; this value is bogus! - * if FS_STATS_DETAILED - * a_bytesToFetchP : Set to the number of bytes to be fetched from - * the File Server. - * a_bytesFetchedP : Set to the actual number of bytes fetched from - * the File Server. - * endif - */ + * a_versionP : Ptr to the version number variable to set. + * + * Returns: + * 0 (always) + * + * Environment: + * Nothing interesting. + * + * Side Effects: + * As advertised. + *------------------------------------------------------------------------*/ -afs_int32 -FetchData_RXStyle(Volume *volptr, - Vnode *targetptr, - register struct rx_call *Call, - afs_int32 Pos, - afs_int32 Len, - afs_int32 Int64Mode, -#if FS_STATS_DETAILED - afs_int32 *a_bytesToFetchP, - afs_int32 *a_bytesFetchedP -#endif /* FS_STATS_DETAILED */ - ) -{ - struct timeval StartTime, StopTime; /* used to calculate file transfer rates */ - int errorCode = 0; /* Returned error code to caller */ - int code; - IHandle_t *ihP; - FdHandle_t *fdP; -#ifdef AFS_NT40_ENV - register char *tbuffer; -#else /* AFS_NT40_ENV */ - struct iovec tiov[RX_MAXIOVECS]; - int tnio; -#endif /* AFS_NT40_ENV */ - afs_int32 tlen; - afs_int32 optSize; - struct stat tstat; -#ifdef AFS_AIX_ENV - struct statfs tstatfs; -#endif +afs_int32 SRXAFS_XStatsVersion(struct rx_call *a_call, afs_int32 *a_versionP) +{ /*SRXAFS_XStatsVersion*/ #if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ + /* - * Initialize the byte count arguments. + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. */ - (*a_bytesToFetchP) = 0; - (*a_bytesFetchedP) = 0; + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_XSTATSVERSION]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ - if (!VN_GET_INO(targetptr)) { - /* - * This is used for newly created files; we simply send 0 bytes - * back to make the cache manager happy... - */ - tlen = htonl(0); - if (Int64Mode) - rx_Write(Call, &tlen, sizeof(afs_int32)); /* send 0-length */ - rx_Write(Call, &tlen, sizeof(afs_int32)); /* send 0-length */ - return (0); - } - TM_GetTimeOfDay(&StartTime, 0); - ihP = targetptr->handle; - fdP = IH_OPEN(ihP); - if (fdP == NULL) return EIO; - optSize = AFSV_BUFFERSIZE; - tlen = FDH_SIZE(fdP); - if (tlen < 0) { - FDH_CLOSE(fdP); - return EIO; - } + *a_versionP = AFS_XSTAT_VERSION; - if (Pos + Len > tlen) Len = tlen - Pos; /* get length we should send */ - FDH_SEEK(fdP, Pos, 0); - tlen = htonl(Len); - if (Int64Mode) { - afs_int32 zero = 0; - rx_Write(Call, &zero, sizeof(afs_int32)); /* High order bits */ - } - rx_Write(Call, &tlen, sizeof(afs_int32)); /* send length on fetch */ -#if FS_STATS_DETAILED - (*a_bytesToFetchP) = Len; -#endif /* FS_STATS_DETAILED */ -#ifdef AFS_NT40_ENV - tbuffer = AllocSendBuffer(); -#endif /* AFS_NT40_ENV */ - while (Len > 0) { - if (Len > optSize) tlen = optSize; - else tlen = Len; -#ifdef AFS_NT40_ENV - errorCode = FDH_READ(fdP, tbuffer, tlen); - if (errorCode != tlen) { - FDH_CLOSE(fdP); - FreeSendBuffer((struct afs_buffer *) tbuffer); - return EIO; - } - errorCode = rx_Write(Call, tbuffer, tlen); -#else /* AFS_NT40_ENV */ - errorCode = rx_WritevAlloc(Call, tiov, &tnio, RX_MAXIOVECS, tlen); - if (errorCode <= 0) { - FDH_CLOSE(fdP); - return EIO; - } - tlen = errorCode; - errorCode = FDH_READV(fdP, tiov, tnio); - if (errorCode != tlen) { - FDH_CLOSE(fdP); - return EIO; - } - errorCode = rx_Writev(Call, tiov, tnio, tlen); -#endif /* AFS_NT40_ENV */ #if FS_STATS_DETAILED - /* - * Bump the number of bytes actually sent by the number from this - * latest iteration - */ - (*a_bytesFetchedP) += errorCode; -#endif /* FS_STATS_DETAILED */ - if (errorCode != tlen) { - FDH_CLOSE(fdP); -#ifdef AFS_NT40_ENV - FreeSendBuffer((struct afs_buffer *) tbuffer); -#endif /* AFS_NT40_ENV */ - return -31; - } - Len -= tlen; + TM_GetTimeOfDay(&opStopTime, 0); + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); } -#ifdef AFS_NT40_ENV - FreeSendBuffer((struct afs_buffer *) tbuffer); -#endif /* AFS_NT40_ENV */ - FDH_CLOSE(fdP); - TM_GetTimeOfDay(&StopTime, 0); - - /* Adjust all Fetch Data related stats */ FS_LOCK - if (AFSCallStats.TotalFetchedBytes > 2000000000) /* Reset if over 2 billion */ - AFSCallStats.TotalFetchedBytes = AFSCallStats.AccumFetchTime = 0; - AFSCallStats.AccumFetchTime += ((StopTime.tv_sec - StartTime.tv_sec) * 1000) + - ((StopTime.tv_usec - StartTime.tv_usec) / 1000); - AFSCallStats.TotalFetchedBytes += targetptr->disk.length; - AFSCallStats.FetchSize1++; - if (targetptr->disk.length < SIZE2) - AFSCallStats.FetchSize2++; - else if (targetptr->disk.length < SIZE3) - AFSCallStats.FetchSize3++; - else if (targetptr->disk.length < SIZE4) - AFSCallStats.FetchSize4++; - else - AFSCallStats.FetchSize5++; + (opP->numSuccesses)++; FS_UNLOCK - return (0); +#endif /* FS_STATS_DETAILED */ -} /*FetchData_RXStyle*/ + return(0); -static int GetLinkCountAndSize(Volume *vp, FdHandle_t *fdP, int *lc, int *size) -{ -#ifdef AFS_NAMEI_ENV - FdHandle_t *lhp; - lhp = IH_OPEN(V_linkHandle(vp)); - if (!lhp) - return EIO; -#ifdef AFS_NT40_ENV - *lc = nt_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0); -#else - *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0); -#endif - FDH_CLOSE(lhp); - if (*lc < 0 ) - return -1; - *size = OS_SIZE(fdP->fd_fd); - return (*size == -1) ? -1 : 0; -#else - struct stat status; +} /*SRXAFS_XStatsVersion*/ + + +/*------------------------------------------------------------------------ + * PRIVATE FillPerfValues + * + * Description: + * Routine called to fill a regular performance data structure. + * + * Arguments: + * a_perfP : Ptr to perf structure to fill + * + * Returns: + * Nothing. + * + * Environment: + * Various collections need this info, so the guts were put in + * this separate routine. + * + * Side Effects: + * As advertised. + *------------------------------------------------------------------------*/ - if (fstat(fdP->fd_fd, &status)<0) { - return -1; - } +static void FillPerfValues(struct afs_PerfStats *a_perfP) +{ /*FillPerfValues*/ - *lc = GetLinkCount(vp, &status); - *size = status.st_size; - return 0; -#endif -} + int dir_Buffers; /*# buffers in use by dir package*/ + int dir_Calls; /*# read calls in dir package*/ + int dir_IOs; /*# I/O ops in dir package*/ -/* - * StoreData_RXStyle + /* + * Vnode cache section. + */ + a_perfP->vcache_L_Entries = VnodeClassInfo[vLarge].cacheSize; + a_perfP->vcache_L_Allocs = VnodeClassInfo[vLarge].allocs; + a_perfP->vcache_L_Gets = VnodeClassInfo[vLarge].gets; + a_perfP->vcache_L_Reads = VnodeClassInfo[vLarge].reads; + a_perfP->vcache_L_Writes = VnodeClassInfo[vLarge].writes; + a_perfP->vcache_S_Entries = VnodeClassInfo[vSmall].cacheSize; + a_perfP->vcache_S_Allocs = VnodeClassInfo[vSmall].allocs; + a_perfP->vcache_S_Gets = VnodeClassInfo[vSmall].gets; + a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads; + a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes; + a_perfP->vcache_H_Entries = VolumeCacheSize; + a_perfP->vcache_H_Gets = VolumeGets; + a_perfP->vcache_H_Replacements = VolumeReplacements; + + /* + * Directory section. + */ + DStat(&dir_Buffers, &dir_Calls, &dir_IOs); + a_perfP->dir_Buffers = (afs_int32) dir_Buffers; + a_perfP->dir_Calls = (afs_int32 )dir_Calls; + a_perfP->dir_IOs = (afs_int32) dir_IOs; + + /* + * Rx section. + */ + a_perfP->rx_packetRequests = + (afs_int32) rx_stats.packetRequests; + a_perfP->rx_noPackets_RcvClass = + (afs_int32) rx_stats.receivePktAllocFailures; + a_perfP->rx_noPackets_SendClass = + (afs_int32) rx_stats.sendPktAllocFailures; + a_perfP->rx_noPackets_SpecialClass = + (afs_int32) rx_stats.specialPktAllocFailures; + a_perfP->rx_socketGreedy = + (afs_int32) rx_stats.socketGreedy; + a_perfP->rx_bogusPacketOnRead = + (afs_int32) rx_stats.bogusPacketOnRead; + a_perfP->rx_bogusHost = + (afs_int32) rx_stats.bogusHost; + a_perfP->rx_noPacketOnRead = + (afs_int32) rx_stats.noPacketOnRead; + a_perfP->rx_noPacketBuffersOnRead = + (afs_int32) rx_stats.noPacketBuffersOnRead; + a_perfP->rx_selects = + (afs_int32) rx_stats.selects; + a_perfP->rx_sendSelects = + (afs_int32) rx_stats.sendSelects; + a_perfP->rx_packetsRead_RcvClass = + (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_RECEIVE]; + a_perfP->rx_packetsRead_SendClass = + (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SEND]; + a_perfP->rx_packetsRead_SpecialClass = + (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SPECIAL]; + a_perfP->rx_dataPacketsRead = + (afs_int32) rx_stats.dataPacketsRead; + a_perfP->rx_ackPacketsRead = + (afs_int32) rx_stats.ackPacketsRead; + a_perfP->rx_dupPacketsRead = + (afs_int32) rx_stats.dupPacketsRead; + a_perfP->rx_spuriousPacketsRead = + (afs_int32) rx_stats.spuriousPacketsRead; + a_perfP->rx_packetsSent_RcvClass = + (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_RECEIVE]; + a_perfP->rx_packetsSent_SendClass = + (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SEND]; + a_perfP->rx_packetsSent_SpecialClass = + (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SPECIAL]; + a_perfP->rx_ackPacketsSent = + (afs_int32) rx_stats.ackPacketsSent; + a_perfP->rx_pingPacketsSent = + (afs_int32) rx_stats.pingPacketsSent; + a_perfP->rx_abortPacketsSent = + (afs_int32) rx_stats.abortPacketsSent; + a_perfP->rx_busyPacketsSent = + (afs_int32) rx_stats.busyPacketsSent; + a_perfP->rx_dataPacketsSent = + (afs_int32) rx_stats.dataPacketsSent; + a_perfP->rx_dataPacketsReSent = + (afs_int32) rx_stats.dataPacketsReSent; + a_perfP->rx_dataPacketsPushed = + (afs_int32) rx_stats.dataPacketsPushed; + a_perfP->rx_ignoreAckedPacket = + (afs_int32) rx_stats.ignoreAckedPacket; + a_perfP->rx_totalRtt_Sec = + (afs_int32) rx_stats.totalRtt.sec; + a_perfP->rx_totalRtt_Usec = + (afs_int32) rx_stats.totalRtt.usec; + a_perfP->rx_minRtt_Sec = + (afs_int32) rx_stats.minRtt.sec; + a_perfP->rx_minRtt_Usec = + (afs_int32) rx_stats.minRtt.usec; + a_perfP->rx_maxRtt_Sec = + (afs_int32) rx_stats.maxRtt.sec; + a_perfP->rx_maxRtt_Usec = + (afs_int32) rx_stats.maxRtt.usec; + a_perfP->rx_nRttSamples = + (afs_int32) rx_stats.nRttSamples; + a_perfP->rx_nServerConns = + (afs_int32) rx_stats.nServerConns; + a_perfP->rx_nClientConns = + (afs_int32) rx_stats.nClientConns; + a_perfP->rx_nPeerStructs = + (afs_int32) rx_stats.nPeerStructs; + a_perfP->rx_nCallStructs = + (afs_int32) rx_stats.nCallStructs; + a_perfP->rx_nFreeCallStructs = + (afs_int32) rx_stats.nFreeCallStructs; + + a_perfP->host_NumHostEntries = HTs; + a_perfP->host_HostBlocks = HTBlocks; + h_GetHostNetStats(&(a_perfP->host_NonDeletedHosts), + &(a_perfP->host_HostsInSameNetOrSubnet), + &(a_perfP->host_HostsInDiffSubnet), + &(a_perfP->host_HostsInDiffNetwork)); + a_perfP->host_NumClients = CEs; + a_perfP->host_ClientBlocks = CEBlocks; + + a_perfP->sysname_ID = afs_perfstats.sysname_ID; + +} /*FillPerfValues*/ + + +/*------------------------------------------------------------------------ + * EXPORTED SRXAFS_GetXStats * - * Purpose: - * Implement a client's data store using Rx. + * Description: + * Routine called by the server-side callback RPC interface to + * implement getting the given data collection from the extended + * File Server statistics. * * Arguments: - * volptr : Ptr to the given volume's info. - * targetptr : Pointer to the vnode involved. - * Call : Ptr to the Rx call involved. - * Pos : Offset within the file. - * Len : Length in bytes to store; this value is bogus! - * if FS_STATS_DETAILED - * a_bytesToStoreP : Set to the number of bytes to be stored to - * the File Server. - * a_bytesStoredP : Set to the actual number of bytes stored to - * the File Server. - * endif - */ -afs_int32 -StoreData_RXStyle(Volume *volptr, - Vnode *targetptr, - struct AFSFid *Fid, - struct client *client, - register struct rx_call *Call, - afs_uint32 Pos, - afs_uint32 Length, - afs_uint32 FileLength, - int sync, -#if FS_STATS_DETAILED - afs_int32 *a_bytesToStoreP, - afs_int32 *a_bytesStoredP -#endif /* FS_STATS_DETAILED */ - ) -{ - int bytesTransfered; /* number of bytes actually transfered */ - struct timeval StartTime, StopTime; /* Used to measure how long the store takes */ - int errorCode = 0; /* Returned error code to caller */ -#ifdef AFS_NT40_ENV - register char *tbuffer; /* data copying buffer */ -#else /* AFS_NT40_ENV */ - struct iovec tiov[RX_MAXIOVECS]; /* no data copying with iovec */ - int tnio; /* temp for iovec size */ -#endif /* AFS_NT40_ENV */ - int tlen; /* temp for xfr length */ - Inode tinode; /* inode for I/O */ - afs_int32 optSize; /* optimal transfer size */ - int DataLength; /* size of inode */ - afs_int32 TruncatedLength; /* size after ftruncate */ - afs_uint32 NewLength; /* size after this store completes */ - afs_int32 adjustSize; /* bytes to call VAdjust... with */ - int linkCount; /* link count on inode */ - int code; - FdHandle_t *fdP; - struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ + * a_call : Ptr to Rx call on which this request came in. + * a_clientVersionNum : Client version number. + * a_opCode : Desired operation. + * a_serverVersionNumP : Ptr to version number to set. + * a_timeP : Ptr to time value (seconds) to set. + * a_dataP : Ptr to variable array structure to return + * stuff in. + * + * Returns: + * 0 (always). + * + * Environment: + * Nothing interesting. + * + * Side Effects: + * As advertised. + *------------------------------------------------------------------------*/ + +afs_int32 SRXAFS_GetXStats(struct rx_call *a_call, + afs_int32 a_clientVersionNum, + afs_int32 a_collectionNumber, + afs_int32 *a_srvVersionNumP, + afs_int32 *a_timeP, + AFS_CollData *a_dataP) +{ /*SRXAFS_GetXStats*/ + register int code; /*Return value*/ + afs_int32 *dataBuffP; /*Ptr to data to be returned*/ + afs_int32 dataBytes; /*Bytes in data buffer*/ #if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ + /* - * Initialize the byte count arguments. + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. */ - (*a_bytesToStoreP) = 0; - (*a_bytesStoredP) = 0; + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETXSTATS]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ /* - * We break the callbacks here so that the following signal will not - * leave a window. + * Record the time of day and the server version number. + */ + *a_srvVersionNumP = AFS_XSTAT_VERSION; + *a_timeP = FT_ApproxTime(); + + /* + * Stuff the appropriate data in there (assume victory) + */ + code = 0; + + ViceLog(1, ("Received GetXStats call for collection %d\n", a_collectionNumber)); + +#if 0 + /* + * We're not keeping stats, so just return successfully with + * no data. */ - BreakCallBack(client->host, Fid, 0); + a_dataP->AFS_CollData_len = 0; + a_dataP->AFS_CollData_val = NULL; +#endif /* 0 */ - if (Pos == -1 || VN_GET_INO(targetptr) == 0) { - /* the inode should have been created in Alloc_NewVnode */ - logHostAddr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(Call))); - ViceLog(0, ("StoreData_RXStyle : Inode non-existent Fid = %u.%d.%d, inode = %d, Pos %d Host %s\n", - Fid->Volume, Fid->Vnode, Fid->Unique, - VN_GET_INO(targetptr), Pos, inet_ntoa(logHostAddr) )); - return ENOENT; /* is this proper error code? */ - } - else { + switch(a_collectionNumber) { + case AFS_XSTATSCOLL_CALL_INFO: /* - * See if the file has several links (from other volumes). If it - * does, then we have to make a copy before changing it to avoid - *changing read-only clones of this dude + * Pass back all the call-count-related data. + * + * >>> We are forced to allocate a separate area in which to + * >>> put this stuff in by the RPC stub generator, since it + * >>> will be freed at the tail end of the server stub code. */ - ViceLog(25, ("StoreData_RXStyle : Opening inode %s\n", - PrintInode(NULL, VN_GET_INO(targetptr)))); - fdP = IH_OPEN(targetptr->handle); - if (fdP == NULL) - return ENOENT; - if (GetLinkCountAndSize(volptr, fdP, &linkCount, - &DataLength)<0) { - FDH_CLOSE(fdP); - return EIO; - } - - if (linkCount != 1) { - afs_uint32 size; - ViceLog(25, ("StoreData_RXStyle : inode %s has more than onelink\n", - PrintInode(NULL, VN_GET_INO(targetptr)))); - /* other volumes share this data, better copy it first */ +#if 0 + /* + * I don't think call-level stats are being collected yet + * for the File Server. + */ + dataBytes = sizeof(struct afs_Stats); + dataBuffP = (afs_int32 *)malloc(dataBytes); + memcpy(dataBuffP, &afs_cmstats, dataBytes); + a_dataP->AFS_CollData_len = dataBytes>>2; + a_dataP->AFS_CollData_val = dataBuffP; +#else + a_dataP->AFS_CollData_len = 0; + a_dataP->AFS_CollData_val = NULL; +#endif /* 0 */ + break; - /* Adjust the disk block count by the creation of the new inode. - * We call the special VDiskUsage so we don't adjust the volume's - * quota since we don't want to penalyze the user for afs's internal - * mechanisms (i.e. copy on write overhead.) Also the right size - * of the disk will be recorded... - */ - FDH_CLOSE(fdP); - size = targetptr->disk.length; - volptr->partition->flags &= ~PART_DONTUPDATE; - VSetPartitionDiskUsage(volptr->partition); - volptr->partition->flags |= PART_DONTUPDATE; - if ((errorCode = VDiskUsage(volptr, nBlocks(size)))) { - volptr->partition->flags &= ~PART_DONTUPDATE; - return(errorCode); - } + case AFS_XSTATSCOLL_PERF_INFO: + /* + * Pass back all the regular performance-related data. + * + * >>> We are forced to allocate a separate area in which to + * >>> put this stuff in by the RPC stub generator, since it + * >>> will be freed at the tail end of the server stub code. + */ - ViceLog(25, ("StoreData : calling CopyOnWrite on target dir\n")); - if ((errorCode = CopyOnWrite(targetptr, volptr))) - { - ViceLog(25, ("StoreData : CopyOnWrite failed\n")); - volptr->partition->flags &= ~PART_DONTUPDATE; - return (errorCode); - } - volptr->partition->flags &= ~PART_DONTUPDATE; - VSetPartitionDiskUsage(volptr->partition); - fdP = IH_OPEN(targetptr->handle); - if (fdP == NULL) { - ViceLog(25, ("StoreData : Reopen after CopyOnWrite failed\n")); - return ENOENT; - } - } - tinode = VN_GET_INO(targetptr); - } - assert(VALID_INO(tinode)); + afs_perfstats.numPerfCalls++; + FillPerfValues(&afs_perfstats); - /* compute new file length */ - NewLength = DataLength; - if (FileLength < NewLength) - /* simulate truncate */ - NewLength = FileLength; - TruncatedLength = NewLength; /* remember length after possible ftruncate */ - if (Pos + Length > NewLength) - NewLength = Pos+Length; /* and write */ + /* + * Don't overwrite the spares at the end. + */ - /* adjust the disk block count by the difference in the files */ - adjustSize = (int) (nBlocks(NewLength) - nBlocks(targetptr->disk.length)); - if((errorCode = AdjustDiskUsage(volptr, adjustSize, - adjustSize - SpareComp(volptr)))) { - FDH_CLOSE(fdP); - return(errorCode); - } + dataBytes = sizeof(struct afs_PerfStats); + dataBuffP = (afs_int32 *)osi_Alloc(dataBytes); + memcpy(dataBuffP, &afs_perfstats, dataBytes); + a_dataP->AFS_CollData_len = dataBytes>>2; + a_dataP->AFS_CollData_val = dataBuffP; + break; - /* can signal cache manager to proceed from close now */ - /* this bit means that the locks are set and protections are OK */ - rx_SetLocalStatus(Call, 1); + case AFS_XSTATSCOLL_FULL_PERF_INFO: + /* + * Pass back the full collection of performance-related data. + * We have to stuff the basic, overall numbers in, but the + * detailed numbers are kept in the structure already. + * + * >>> We are forced to allocate a separate area in which to + * >>> put this stuff in by the RPC stub generator, since it + * >>> will be freed at the tail end of the server stub code. + */ - TM_GetTimeOfDay(&StartTime, 0); + afs_perfstats.numPerfCalls++; +#if FS_STATS_DETAILED + afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls; + FillPerfValues(&afs_FullPerfStats.overall); - optSize = AFSV_BUFFERSIZE; + /* + * Don't overwrite the spares at the end. + */ - /* truncate the file iff it needs it (ftruncate is slow even when its a noop) */ - if (FileLength < DataLength) FDH_TRUNC(fdP, FileLength); - if (Pos > 0) FDH_SEEK(fdP, Pos, 0); - bytesTransfered = 0; -#ifdef AFS_NT40_ENV - tbuffer = AllocSendBuffer(); -#endif /* AFS_NT40_ENV */ - /* if length == 0, the loop below isn't going to do anything, including - * extend the length of the inode, which it must do, since the file system - * assumes that the inode length == vnode's file length. So, we extend - * the file length manually if need be. Note that if file is bigger than - * Pos+(Length==0), we dont' have to do anything, and certainly shouldn't - * do what we're going to do below. - */ - if (Length == 0 && Pos > TruncatedLength) { - /* Set the file's length; we've already done an lseek to the right - * spot above. + dataBytes = sizeof(struct fs_stats_FullPerfStats); + dataBuffP = (afs_int32 *)osi_Alloc(dataBytes); + memcpy(dataBuffP, &afs_FullPerfStats, dataBytes); + a_dataP->AFS_CollData_len = dataBytes>>2; + a_dataP->AFS_CollData_val = dataBuffP; +#endif + break; + + default: + /* + * Illegal collection number. */ - errorCode = FDH_WRITE(fdP, &tlen, 1); - if (errorCode != 1) goto done; - errorCode = FDH_TRUNC(fdP, Pos); - } - else { - /* have some data to copy */ -#if FS_STATS_DETAILED - (*a_bytesToStoreP) = Length; -#endif /* FS_STATS_DETAILED */ - while (1) { - if (bytesTransfered >= Length) { - errorCode = 0; - break; - } - tlen = Length - bytesTransfered; /* how much more to do */ - if (tlen > optSize) tlen = optSize; /* bound by buffer size */ -#ifdef AFS_NT40_ENV - errorCode = rx_Read(Call, tbuffer, tlen); -#else /* AFS_NT40_ENV */ - errorCode = rx_Readv(Call, tiov, &tnio, RX_MAXIOVECS, tlen); -#endif /* AFS_NT40_ENV */ + a_dataP->AFS_CollData_len = 0; + a_dataP->AFS_CollData_val = NULL; + code = 1; + } /*Switch on collection number*/ + #if FS_STATS_DETAILED - (*a_bytesStoredP) += errorCode; -#endif /* FS_STATS_DETAILED */ - if (errorCode <= 0) { - errorCode = -32; - break; - } - tlen = errorCode; -#ifdef AFS_NT40_ENV - errorCode = FDH_WRITE(fdP, tbuffer, tlen); -#else /* AFS_NT40_ENV */ - errorCode = FDH_WRITEV(fdP, tiov, tnio); -#endif /* AFS_NT40_ENV */ - if (errorCode != tlen) { - errorCode = VDISKFULL; - break; - } - bytesTransfered += tlen; - } - } - done: -#ifdef AFS_NT40_ENV - FreeSendBuffer((struct afs_buffer *) tbuffer); -#endif /* AFS_NT40_ENV */ - if (sync) { - FDH_SYNC(fdP); - } - if (errorCode) { - /* something went wrong: adjust size and return */ - targetptr->disk.length = FDH_SIZE(fdP); /* set new file size. */ - /* changed_newTime is tested in StoreData to detemine if we - * need to update the target vnode. - */ - targetptr->changed_newTime = 1; - FDH_CLOSE(fdP); - /* set disk usage to be correct */ - VAdjustDiskUsage(&errorCode, volptr, - (int)(nBlocks(targetptr->disk.length) - - nBlocks(NewLength)), 0); - return errorCode; + TM_GetTimeOfDay(&opStopTime, 0); + if (code == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK } - FDH_CLOSE(fdP); - - TM_GetTimeOfDay(&StopTime, 0); - targetptr->disk.length = NewLength; +#endif /* FS_STATS_DETAILED */ - /* Update all StoreData related stats */ - FS_LOCK - if (AFSCallStats.TotalStoredBytes > 2000000000) /* reset if over 2 billion */ - AFSCallStats.TotalStoredBytes = AFSCallStats.AccumStoreTime = 0; - AFSCallStats.StoreSize1++; /* Piggybacked data */ - if (targetptr->disk.length < SIZE2) - AFSCallStats.StoreSize2++; - else if (targetptr->disk.length < SIZE3) - AFSCallStats.StoreSize3++; - else if (targetptr->disk.length < SIZE4) - AFSCallStats.StoreSize4++; - else - AFSCallStats.StoreSize5++; - FS_UNLOCK - return(errorCode); + return(code); -} /*StoreData_RXStyle*/ +} /*SRXAFS_GetXStats*/ -/* - * Check if target file has the proper access permissions for the Fetch - * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL, - * StoreStatus) related calls - */ -/* this code should probably just set a "priv" flag where all the audit events - * are now, and only generate the audit event once at the end of the routine, - * thus only generating the event if all the checks succeed, but only because - * of the privilege XXX - */ -static afs_int32 -Check_PermissionRights(Vnode *targetptr, - struct client *client, - afs_int32 rights, - int CallingRoutine, - AFSStoreStatus *InStatus) +afs_int32 SRXAFS_GiveUpCallBacks (struct rx_call *acall, + struct AFSCBFids *FidArray, + struct AFSCBs *CallBackArray) { - int errorCode = 0; -#define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner) -#define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner)) -#define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group)) - - if (CallingRoutine & CHK_FETCH) { -#ifdef CMUCS - if (VanillaUser(client)) -#else - if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client)) -#endif - { - if (targetptr->disk.type == vDirectory || targetptr->disk.type == vSymlink) { - if ( !(rights & PRSFS_LOOKUP) -#ifdef ADMIN_IMPLICIT_LOOKUP - /* grant admins fetch on all directories */ - && VanillaUser(client) -#endif /* ADMIN_IMPLICIT_LOOKUP */ - && !VolumeOwner(client, targetptr)) - return(EACCES); - } else { /* file */ - /* must have read access, or be owner and have insert access */ - if (!(rights & PRSFS_READ) && - !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT))) - return(EACCES); - } - if (CallingRoutine == CHK_FETCHDATA && targetptr->disk.type == vFile) -#ifdef USE_GROUP_PERMS - if (!OWNSp(client, targetptr) && - !acl_IsAMember(targetptr->disk.owner, &client->CPS)) { - errorCode = (((GROUPREAD|GROUPEXEC) & targetptr->disk.modeBits) - ? 0: EACCES); - } else { - errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits) - ? 0: EACCES); - } -#else - /* - * The check with the ownership below is a kludge to allow - * reading of files created with no read permission. The owner - * of the file is always allowed to read it. - */ - if ((client->ViceId != targetptr->disk.owner) && VanillaUser(client)) - errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits) ? 0: EACCES); -#endif - } - else /* !VanillaUser(client) && !FetchData */ { - osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), - AUD_INT, CallingRoutine, AUD_END); - } - } - else { /* a store operation */ - if ( (rights & PRSFS_INSERT) && OWNSp(client, targetptr) - && (CallingRoutine != CHK_STOREACL) - && (targetptr->disk.type == vFile)) - { - /* bypass protection checks on first store after a create - * for the creator; also prevent chowns during this time - * unless you are a system administrator */ - /****** InStatus->Owner && UnixModeBits better be SET!! */ - if ( CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) { - if (readonlyServer) - return(VREADONLY); - else if (VanillaUser (client)) - return(EPERM); /* Was EACCES */ - else - osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), - AUD_INT, CallingRoutine, AUD_END); - } - } else { - if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) { - osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), - AUD_INT, CallingRoutine, AUD_END); - } - else { - if (readonlyServer) { - return(VREADONLY); - } - if (CallingRoutine == CHK_STOREACL) { - if (!(rights & PRSFS_ADMINISTER) && - !VolumeOwner(client, targetptr)) return(EACCES); - } - else { /* store data or status */ - /* watch for chowns and chgrps */ - if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) { - if (readonlyServer) - return(VREADONLY); - else if (VanillaUser (client)) - return(EPERM); /* Was EACCES */ - else - osi_audit(PrivilegeEvent, 0, - AUD_INT, (client ? client->ViceId : 0), - AUD_INT, CallingRoutine, AUD_END); - } - /* must be sysadmin to set suid/sgid bits */ - if ((InStatus->Mask & AFS_SETMODE) && -#ifdef AFS_NT40_ENV - (InStatus->UnixModeBits & 0xc00) != 0) { -#else - (InStatus->UnixModeBits & (S_ISUID|S_ISGID)) != 0) { -#endif - if (readonlyServer) - return(VREADONLY); - if (VanillaUser(client)) - return(EACCES); - else osi_audit( PrivSetID, 0, AUD_INT, (client ? client->ViceId : 0), - AUD_INT, CallingRoutine, AUD_END); - } - if (CallingRoutine == CHK_STOREDATA) { - if (readonlyServer) - return(VREADONLY); - if (!(rights & PRSFS_WRITE)) - return(EACCES); - /* Next thing is tricky. We want to prevent people - * from writing files sans 0200 bit, but we want - * creating new files with 0444 mode to work. We - * don't check the 0200 bit in the "you are the owner" - * path above, but here we check the bit. However, if - * you're a system administrator, we ignore the 0200 - * bit anyway, since you may have fchowned the file, - * too */ -#ifdef USE_GROUP_PERMS - if ((targetptr->disk.type == vFile) - && VanillaUser(client)) { - if (!OWNSp(client, targetptr) && - !acl_IsAMember(targetptr->disk.owner, - &client->CPS)) { - errorCode = ((GROUPWRITE & targetptr->disk.modeBits) - ? 0: EACCES); - } else { - errorCode = ((OWNERWRITE & targetptr->disk.modeBits) - ? 0 : EACCES); - } - } else -#endif - if ((targetptr->disk.type != vDirectory) - && (!(targetptr->disk.modeBits & OWNERWRITE))) - if (readonlyServer) - return(VREADONLY); - if (VanillaUser(client)) - return(EACCES); - else osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), - AUD_INT, CallingRoutine, AUD_END); - } - else { /* a status store */ - if (readonlyServer) - return(VREADONLY); - if (targetptr->disk.type == vDirectory) { - if (!(rights & PRSFS_DELETE) && !(rights & PRSFS_INSERT)) - return(EACCES); - } - else { /* a file or symlink */ - if (!(rights & PRSFS_WRITE)) return(EACCES); - } - } - } - } - } - } - return(errorCode); - -} /*Check_PermissionRights*/ + afs_int32 errorCode; + register int i; + struct client *client; + struct rx_connection *tcon; +#if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ + /* + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. + */ + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GIVEUPCALLBACKS]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ -/* - * The Access List information is converted from its internal form in the - * target's vnode buffer (or its parent vnode buffer if not a dir), to an - * external form and returned back to the caller, via the AccessList - * structure - */ -static afs_int32 -RXFetch_AccessList(Vnode *targetptr, - Vnode *parentwhentargetnotdir, - struct AFSOpaque *AccessList) -{ - char * eACL; /* External access list placeholder */ + ViceLog(1, ("SAFS_GiveUpCallBacks (Noffids=%d)\n", FidArray->AFSCBFids_len)); + FS_LOCK + AFSCallStats.GiveUpCallBacks++, AFSCallStats.TotalCalls++; + FS_UNLOCK + if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_GiveUpCallBacks; - if (acl_Externalize((targetptr->disk.type == vDirectory ? - VVnodeACL(targetptr) : - VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) { - return EIO; - } - if ((strlen(eACL)+1) > AFSOPAQUEMAX) { - acl_FreeExternalACL(&eACL); - return(E2BIG); - } else { - strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL); - AccessList->AFSOpaque_len = strlen(eACL) +1; + if (FidArray->AFSCBFids_len < CallBackArray->AFSCBs_len) { + ViceLog(0, ("GiveUpCallBacks: #Fids %d < #CallBacks %d, host=%x\n", + FidArray->AFSCBFids_len, CallBackArray->AFSCBs_len, + (tcon->peer ? tcon->peer->host : 0))); + errorCode = EINVAL; + goto Bad_GiveUpCallBacks; } - acl_FreeExternalACL(&eACL); - return(0); - -} /*RXFetch_AccessList*/ + errorCode = GetClient(tcon, &client); + if (!errorCode) { + for (i=0; i < FidArray->AFSCBFids_len; i++) { + register struct AFSFid *fid = &(FidArray->AFSCBFids_val[i]); + DeleteCallBack(client->host, fid); + } + } -/* - * The Access List information is converted from its external form in the - * input AccessList structure to the internal representation and copied into - * the target dir's vnode storage. - */ -static afs_int32 -RXStore_AccessList(Vnode *targetptr, struct AFSOpaque *AccessList) -{ - struct acl_accessList * newACL; /* PlaceHolder for new access list */ +Bad_GiveUpCallBacks: + CallPostamble(tcon); - if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0) - return(EINVAL); - if ((newACL->size + 4) > VAclSize(targetptr)) - return(E2BIG); - memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size)); - acl_FreeACL(&newACL); - return(0); +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (errorCode == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK + } +#endif /* FS_STATS_DETAILED */ +out: + return errorCode; -} /*RXStore_AccessList*/ +} /*SRXAFS_GiveUpCallBacks*/ -static afs_int32 -Fetch_AccessList(Vnode *targetptr, Vnode *parentwhentargetnotdir, - struct AFSAccessList *AccessList) +afs_int32 SRXAFS_NGetVolumeInfo (struct rx_call *acall, + char *avolid, + struct AFSVolumeInfo *avolinfo) { - char * eACL; /* External access list placeholder */ + return(VNOVOL); /* XXX Obsolete routine XXX */ - assert(acl_Externalize((targetptr->disk.type == vDirectory ? - VVnodeACL(targetptr) : - VVnodeACL(parentwhentargetnotdir)), &eACL) == 0); - if ((strlen(eACL)+1) > AccessList->MaxSeqLen) { - acl_FreeExternalACL(&eACL); - return(E2BIG); - } else { - strcpy((char *)(AccessList->SeqBody), (char *)eACL); - AccessList->SeqLen = strlen(eACL) +1; - } - acl_FreeExternalACL(&eACL); - return(0); +} /*SRXAFS_NGetVolumeInfo*/ -} /*Fetch_AccessList*/ /* - * The Access List information is converted from its external form in the - * input AccessList structure to the internal representation and copied into - * the target dir's vnode storage. + * Dummy routine. Should never be called (the cache manager should only + * invoke this interface when communicating with a AFS/DFS Protocol + * Translator). */ -static afs_int32 -Store_AccessList(Vnode *targetptr, struct AFSAccessList *AccessList) +afs_int32 SRXAFS_Lookup(struct rx_call *call_p, + struct AFSFid *afs_dfid_p, + char *afs_name_p, + struct AFSFid *afs_fid_p, + struct AFSFetchStatus *afs_status_p, + struct AFSFetchStatus *afs_dir_status_p, + struct AFSCallBack *afs_callback_p, + struct AFSVolSync *afs_sync_p) { - struct acl_accessList * newACL; /* PlaceHolder for new access list */ - - if (acl_Internalize(AccessList->SeqBody, &newACL) != 0) - return(EINVAL); - if ((newACL->size + 4) > VAclSize(targetptr)) - return(E2BIG); - memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size)); - acl_FreeACL(&newACL); - return(0); - -} /*Store_AccessList*/ + return EINVAL; +} -/* - * Common code to handle with removing the Name (file when it's called from - * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a - * given directory, parentptr. - */ -int DT1=0, DT0=0; -static afs_int32 -DeleteTarget(Vnode *parentptr, - Volume *volptr, - Vnode **targetptr, - DirHandle *dir, - AFSFid *fileFid, - char *Name, - int ChkForDir) +afs_int32 SRXAFS_FlushCPS(struct rx_call *acall, + struct ViceIds *vids, + struct IPAddrs *addrs, + afs_int32 spare1, + afs_int32 *spare2, + afs_int32 *spare3) { - DirHandle childdir; /* Handle for dir package I/O */ - int errorCode = 0; - int code; + int i; + afs_int32 nids, naddrs; + afs_int32 *vd, *addr; + int errorCode = 0; /* return code to caller */ + struct client *client; + struct rx_connection *tcon = rx_ConnectionOf(acall); - /* watch for invalid names */ - if (!strcmp(Name, ".") || !strcmp(Name, "..")) - return (EINVAL); - if (parentptr->disk.cloned) - { - ViceLog(25, ("DeleteTarget : CopyOnWrite called\n")); - if ((errorCode = CopyOnWrite(parentptr, volptr))) - { - ViceLog(20, ("DeleteTarget %s: CopyOnWrite failed %d\n",Name,errorCode)); - return errorCode; - } + ViceLog(1, ("SRXAFS_FlushCPS\n")); + FS_LOCK + AFSCallStats.TotalCalls++; + FS_UNLOCK + nids = vids->ViceIds_len; /* # of users in here */ + naddrs = addrs->IPAddrs_len; /* # of hosts in here */ + if (nids < 0 || naddrs < 0) { + errorCode = EINVAL; + goto Bad_FlushCPS; } - /* check that the file is in the directory */ - SetDirHandle(dir, parentptr); - if (Lookup(dir, Name, fileFid)) - return(ENOENT); - fileFid->Volume = V_id(volptr); - - /* just-in-case check for something causing deadlock */ - if (fileFid->Vnode == parentptr->vnodeNumber) - return(EINVAL); + vd = vids->ViceIds_val; + for (i=0; iVnode, WRITE_LOCK); - if (errorCode) { - return (errorCode); - } - if (ChkForDir == MustBeDIR) { - if ((*targetptr)->disk.type != vDirectory) - return(ENOTDIR); - } else if ((*targetptr)->disk.type == vDirectory) - return(EISDIR); - - /*assert((*targetptr)->disk.uniquifier == fileFid->Unique);*/ - /** - * If the uniquifiers dont match then instead of asserting - * take the volume offline and return VSALVAGE - */ - if ( (*targetptr)->disk.uniquifier != fileFid->Unique ) { - VTakeOffline(volptr); - errorCode = VSALVAGE; - return errorCode; - } - - if (ChkForDir == MustBeDIR) { - SetDirHandle(&childdir, *targetptr); - if (IsEmpty(&childdir) != 0) - return(EEXIST); - DZap(&childdir); - (*targetptr)->delete = 1; - } else if ((--(*targetptr)->disk.linkCount) == 0) - (*targetptr)->delete = 1; - if ((*targetptr)->delete) { - if (VN_GET_INO(*targetptr)) { - DT0++; - IH_REALLYCLOSE((*targetptr)->handle); - errorCode = IH_DEC(V_linkHandle(volptr), - VN_GET_INO(*targetptr), - V_parentId(volptr)); - IH_RELEASE((*targetptr)->handle); - if (errorCode == -1) { - ViceLog(0, ("DT: inode=%s, name=%s, errno=%d\n", - PrintInode(NULL, VN_GET_INO(*targetptr)), - Name, errno)); -#ifdef AFS_DEC_ENV - if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO)) -#else - if (errno != ENOENT) + BoostSharedLock(&client->lock); + client->prfail = 2; /* Means re-eval client's cps */ +#ifdef notdef + if (client->tcon) { + rx_SetRock(((struct rx_connection *) client->tcon), 0); + } #endif - { - ViceLog(0, ("Volume %u now offline, must be salvaged.\n", - volptr->hashid)); - VTakeOffline(volptr); - return (EIO); - } - DT1++; - errorCode = 0; - } - } - VN_SET_INO(*targetptr, (Inode)0); - VAdjustDiskUsage(&errorCode, volptr, - -(int)nBlocks((*targetptr)->disk.length), 0); + if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) { + free(client->CPS.prlist_val); + client->CPS.prlist_val = NULL; + } + ReleaseWriteLock(&client->lock); } - - (*targetptr)->changed_newTime = 1; /* Status change of deleted file/dir */ - code = Delete(dir,(char *) Name); - if (code) { - ViceLog(0, ("Error %d deleting %s\n", code, - (((*targetptr)->disk.type== Directory)?"directory":"file"))); - ViceLog(0, ("Volume %u now offline, must be salvaged.\n", - volptr->hashid)); - VTakeOffline(volptr); - if (!errorCode) errorCode = code; + addr = addrs->IPAddrs_val; + for (i=0; i '9' || tc < '0') return 0; /* invalid name */ + temp *= 10; + temp += tc - '0'; + } + return temp; +} /* - * This routine updates the parent directory's status block after the - * specified operation (i.e. RemoveFile(), CreateFile(), Rename(), - * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has - * been performed. + * may get name or #, but must handle all weird cases (recognize readonly + * or backup volumes by name or # */ -static void -Update_ParentVnodeStatus(Vnode *parentptr, - Volume *volptr, - DirHandle *dir, - int author, - int linkcount, -#if FS_STATS_DETAILED - char a_inSameNetwork; -#endif /* FS_STATS_DETAILED */ - ) +static afs_int32 CopyVolumeEntry(char *aname,register struct vldbentry *ave, + register struct VolumeInfo *av) { - afs_uint32 newlength; /* Holds new directory length */ - int errorCode; -#if FS_STATS_DETAILED - Date currDate; /*Current date*/ - int writeIdx; /*Write index to bump*/ - int timeIdx; /*Authorship time index to bump*/ -#endif /* FS_STATS_DETAILED */ - - parentptr->disk.dataVersion++; - newlength = Length(dir); - /* - * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions - * (create, symlink, link, makedir) so we need to check if we have enough space - * XXX But we still don't check the error since we're dealing with dirs here and really the increase - * of a new entry would be too tiny to worry about failures (since we have all the existing cushion) - */ - if (nBlocks(newlength) != nBlocks(parentptr->disk.length)) - VAdjustDiskUsage(&errorCode, volptr, - (int)(nBlocks(newlength) - nBlocks(parentptr->disk.length)), - (int)(nBlocks(newlength) - nBlocks(parentptr->disk.length))); - parentptr->disk.length = newlength; - -#if FS_STATS_DETAILED + register int i, j, vol; + afs_int32 mask, whichType; + afs_uint32 *serverHost, *typePtr; + + /* figure out what type we want if by name */ + i = strlen(aname); + if (i >= 8 && strcmp(aname+i-7, ".backup") == 0) + whichType = BACKVOL; + else if (i >= 10 && strcmp(aname+i-9, ".readonly")==0) + whichType = ROVOL; + else whichType = RWVOL; + + vol = afs_vtoi(aname); + if (vol == 0) vol = ave->volumeId[whichType]; + /* - * Update directory write stats for this volume. Note that the auth - * counter is located immediately after its associated ``distance'' - * counter. + * Now vol has volume # we're interested in. Next, figure out the type + * of the volume by looking finding it in the vldb entry */ - if (a_inSameNetwork) - writeIdx = VOL_STATS_SAME_NET; + if ((ave->flags&VLF_RWEXISTS) && vol == ave->volumeId[RWVOL]) { + mask = VLSF_RWVOL; + whichType = RWVOL; + } + else if ((ave->flags&VLF_ROEXISTS) && vol == ave->volumeId[ROVOL]) { + mask = VLSF_ROVOL; + whichType = ROVOL; + } + else if ((ave->flags&VLF_BACKEXISTS) && vol == ave->volumeId[BACKVOL]) { + mask = VLSF_RWVOL; /* backup always is on the same volume as parent */ + whichType = BACKVOL; + } else - writeIdx = VOL_STATS_DIFF_NET; - V_stat_writes(volptr, writeIdx)++; - if (author != AnonymousID) { - V_stat_writes(volptr, writeIdx+1)++; + return EINVAL; /* error: can't find volume in vldb entry */ + + typePtr = &av->Type0; + serverHost = &av->Server0; + av->Vid = vol; + av->Type = whichType; + av->Type0 = av->Type1 = av->Type2 = av->Type3 = av->Type4 = 0; + if (ave->flags & VLF_RWEXISTS) typePtr[RWVOL] = ave->volumeId[RWVOL]; + if (ave->flags & VLF_ROEXISTS) typePtr[ROVOL] = ave->volumeId[ROVOL]; + if (ave->flags & VLF_BACKEXISTS) typePtr[BACKVOL] = ave->volumeId[BACKVOL]; + + for(i=0,j=0; inServers; i++) { + if ((ave->serverFlags[i] & mask) == 0) continue; /* wrong volume */ + serverHost[j] = ave->serverNumber[i]; + j++; } + av->ServerCount = j; + if (j < 8) serverHost[j++] = 0; /* bogus 8, but compat only now */ + return 0; +} - /* - * Update the volume's authorship information in response to this - * directory operation. Get the current time, decide to which time - * slot this operation belongs, and bump the appropriate slot. - */ - currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime); - timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : - currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : - currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : - currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : - currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 : - VOL_STATS_TIME_IDX_5); - if (parentptr->disk.author == author) { - V_stat_dirSameAuthor(volptr, timeIdx)++; +static afs_int32 TryLocalVLServer(char *avolid, struct VolumeInfo *avolinfo) +{ + static struct rx_connection *vlConn = 0; + static int down = 0; + static afs_int32 lastDownTime = 0; + struct vldbentry tve; + struct rx_securityClass *vlSec; + register afs_int32 code; + + if (!vlConn) { + vlSec = rxnull_NewClientSecurityObject(); + vlConn = rx_NewConnection(htonl(0x7f000001), htons(7003), 52, vlSec, 0); + rx_SetConnDeadTime(vlConn, 15); /* don't wait long */ } - else { - V_stat_dirDiffAuthor(volptr, timeIdx)++; + if (down && (FT_ApproxTime() < lastDownTime + 180)) { + return 1; /* failure */ } -#endif /* FS_STATS_DETAILED */ - parentptr->disk.author = author; - parentptr->disk.linkCount = linkcount; - parentptr->disk.unixModifyTime = FT_ApproxTime(); /* This should be set from CLIENT!! */ - parentptr->disk.serverModifyTime = FT_ApproxTime(); - parentptr->changed_newTime = 1; /* vnode changed, write it back. */ + code = VL_GetEntryByNameO(vlConn, avolid, &tve); + if (code >= 0) down = 0; /* call worked */ + if (code) { + if (code < 0) { + lastDownTime = FT_ApproxTime(); /* last time we tried an RPC */ + down = 1; + } + return code; + } + + /* otherwise convert to old format vldb entry */ + code = CopyVolumeEntry(avolid, &tve, avolinfo); + return code; } -/* - * Update the target file's (or dir's) status block after the specified - * operation is complete. Note that some other fields maybe updated by - * the individual module. - */ -/* XXX INCOMPLETE - More attention is needed here! */ -static void -Update_TargetVnodeStatus(Vnode *targetptr, - afs_uint32 Caller, - struct client *client, - AFSStoreStatus *InStatus, - Vnode *parentptr, - Volume *volptr, - afs_int32 length) -{ -#if FS_STATS_DETAILED - Date currDate; /*Current date*/ - int writeIdx; /*Write index to bump*/ - int timeIdx; /*Authorship time index to bump*/ -#endif /* FS_STATS_DETAILED */ - if (Caller & (TVS_CFILE|TVS_SLINK|TVS_MKDIR)) { /* initialize new file */ - targetptr->disk.parent = parentptr->vnodeNumber; - targetptr->disk.length = length; - /* targetptr->disk.group = 0; save some cycles */ - targetptr->disk.modeBits = 0777; - targetptr->disk.owner = client->ViceId; - targetptr->disk.dataVersion = 0 ; /* consistent with the client */ - targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1); - /* the inode was created in Alloc_NewVnode() */ - } + +afs_int32 SRXAFS_GetVolumeInfo (struct rx_call *acall, + char *avolid, + struct VolumeInfo *avolinfo) +{ + afs_int32 code; + struct rx_connection *tcon; #if FS_STATS_DETAILED - /* - * Update file write stats for this volume. Note that the auth - * counter is located immediately after its associated ``distance'' - * counter. - */ - if (client->InSameNetwork) - writeIdx = VOL_STATS_SAME_NET; - else - writeIdx = VOL_STATS_DIFF_NET; - V_stat_writes(volptr, writeIdx)++; - if (client->ViceId != AnonymousID) { - V_stat_writes(volptr, writeIdx+1)++; - } + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ /* - * We only count operations that DON'T involve creating new objects - * (files, symlinks, directories) or simply setting status as - * authorship-change operations. + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. */ - if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) { - /* - * Update the volume's authorship information in response to this - * file operation. Get the current time, decide to which time - * slot this operation belongs, and bump the appropriate slot. - */ - currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime); - timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : - currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : - currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : - currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : - currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 : - VOL_STATS_TIME_IDX_5); - if (targetptr->disk.author == client->ViceId) { - V_stat_fileSameAuthor(volptr, timeIdx)++; - } else { - V_stat_fileDiffAuthor(volptr, timeIdx)++; - } - } + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMEINFO]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); #endif /* FS_STATS_DETAILED */ + if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_GetVolumeInfo; + + FS_LOCK + AFSCallStats.GetVolumeInfo++, AFSCallStats.TotalCalls++; + FS_UNLOCK + + code = TryLocalVLServer(avolid, avolinfo); + ViceLog(1, ("SAFS_GetVolumeInfo returns %d, Volume %u, type %x, servers %x %x %x %x...\n", + code, avolinfo->Vid, avolinfo->Type, + avolinfo->Server0, avolinfo->Server1, avolinfo->Server2, + avolinfo->Server3)); + avolinfo->Type4 = 0xabcd9999; /* tell us to try new vldb */ + +Bad_GetVolumeInfo: + CallPostamble(tcon); - if (!(Caller & TVS_SSTATUS)) - targetptr->disk.author = client->ViceId; - if (Caller & TVS_SDATA) { - targetptr->disk.dataVersion++; - if (VanillaUser(client)) - { - targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */ -#ifdef CREATE_SGUID_ADMIN_ONLY - targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */ -#endif - } - } - if (Caller & TVS_SSTATUS) { /* update time on non-status change */ - /* store status, must explicitly request to change the date */ - if (InStatus->Mask & AFS_SETMODTIME) - targetptr->disk.unixModifyTime = InStatus->ClientModTime; - } - else {/* other: date always changes, but perhaps to what is specified by caller */ - targetptr->disk.unixModifyTime = (InStatus->Mask & AFS_SETMODTIME ? InStatus->ClientModTime : FT_ApproxTime()); +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (code == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK } - if (InStatus->Mask & AFS_SETOWNER) { - /* admin is allowed to do chmod, chown as well as chown, chmod. */ - if (VanillaUser(client)) - { - targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */ -#ifdef CREATE_SGUID_ADMIN_ONLY - targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */ -#endif - } - targetptr->disk.owner = InStatus->Owner; - if (VolumeRootVnode (targetptr)) { - Error errorCode = 0; /* what should be done with this? */ - V_owner(targetptr->volumePtr) = InStatus->Owner; - VUpdateVolume(&errorCode, targetptr->volumePtr); - } - } - if (InStatus->Mask & AFS_SETMODE) { - int modebits = InStatus->UnixModeBits; -#define CREATE_SGUID_ADMIN_ONLY 1 -#ifdef CREATE_SGUID_ADMIN_ONLY - if (VanillaUser(client)) - modebits = modebits & 0777; -#endif - if (VanillaUser(client)) { - targetptr->disk.modeBits = modebits; - } - else { - targetptr->disk.modeBits = modebits; - switch ( Caller ) { - case TVS_SDATA: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId, - AUD_INT, CHK_STOREDATA, AUD_END); break; - case TVS_CFILE: - case TVS_SSTATUS: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId, - AUD_INT, CHK_STORESTATUS, AUD_END); break; - default: break; - } - } - } - targetptr->disk.serverModifyTime = FT_ApproxTime(); - if (InStatus->Mask & AFS_SETGROUP) - targetptr->disk.group = InStatus->Group; - /* vnode changed : to be written back by VPutVnode */ - targetptr->changed_newTime = 1; +#endif /* FS_STATS_DETAILED */ -} /*Update_TargetVnodeStatus*/ + return code; +} /*SRXAFS_GetVolumeInfo*/ -/* - * Fills the CallBack structure with the expiration time and type of callback - * structure. Warning: this function is currently incomplete. - */ -static void -SetCallBackStruct(afs_uint32 CallBackTime, struct AFSCallBack *CallBack) + +afs_int32 SRXAFS_GetVolumeStatus(struct rx_call *acall, + afs_int32 avolid, + AFSFetchVolumeStatus *FetchVolStatus, + char **Name, + char **OfflineMsg, + char **Motd) { - /* CallBackTime could not be 0 */ - if (CallBackTime == 0) { - ViceLog(0, ("WARNING: CallBackTime == 0!\n")); - CallBack->ExpirationTime = 0; - } else - CallBack->ExpirationTime = CallBackTime - FT_ApproxTime(); - CallBack->CallBackVersion = CALLBACK_VERSION; - CallBack->CallBackType = CB_SHARED; /* The default for now */ + Vnode * targetptr = 0; /* vnode of the new file */ + 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 */ + afs_int32 rights, anyrights; /* rights for this and any user */ + AFSFid dummyFid; + struct rx_connection *tcon; +#if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ -} /*SetCallBackStruct*/ + /* + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. + */ + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMESTATUS]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ + + ViceLog(1,("SAFS_GetVolumeStatus for volume %u\n", avolid)); + if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_GetVolumeStatus; + FS_LOCK + AFSCallStats.GetVolumeStatus++, AFSCallStats.TotalCalls++; + FS_UNLOCK -/* - * Returns the volume and vnode pointers associated with file Fid; the lock - * type on the vnode is set to lock. Note that both volume/vnode's ref counts - * are incremented and they must be eventualy released. - */ -static afs_int32 -CheckVnode(AFSFid *fid, Volume **volptr, Vnode **vptr, int lock) -{ - int fileCode = 0; - int errorCode = -1; - static struct timeval restartedat = {0,0}; + if (avolid == 0) { + errorCode = EINVAL; + goto Bad_GetVolumeStatus; + } + dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1; - if (fid->Volume == 0 || fid->Vnode == 0) /* not: || fid->Unique == 0) */ - return(EINVAL); - if ((*volptr) == 0) { - extern int VInit; + if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr, + MustBeDIR, &parentwhentargetnotdir, + &client, READ_LOCK, &rights, &anyrights))) + goto Bad_GetVolumeStatus; - while(1) { - errorCode = 0; - *volptr = VGetVolume(&errorCode, (afs_int32)fid->Volume); - if (!errorCode) { - assert (*volptr); - break; - } - if ((errorCode == VOFFLINE) && (VInit < 2)) { - /* The volume we want may not be attached yet because - * the volume initialization is not yet complete. - * We can do several things: - * 1. return -1, which will cause users to see - * "connection timed out". This is more or - * less the same as always, except that the servers - * may appear to bounce up and down while they - * are actually restarting. - * 2. return VBUSY which will cause clients to - * sleep and retry for 6.5 - 15 minutes, depending - * on what version of the CM they are running. If - * the file server takes longer than that interval - * to attach the desired volume, then the application - * will see an ENODEV or EIO. This approach has - * the advantage that volumes which have been attached - * are immediately available, it keeps the server's - * immediate backlog low, and the call is interruptible - * by the user. Users see "waiting for busy volume." - * 3. sleep here and retry. Some people like this approach - * because there is no danger of seeing errors. However, - * this approach only works with a bounded number of - * clients, since the pending queues will grow without - * stopping. It might be better to find a way to take - * this call and stick it back on a queue in order to - * recycle this thread for a different request. - * 4. Return a new error code, which new cache managers will - * know enough to interpret as "sleep and retry", without - * the upper bound of 6-15 minutes that is imposed by the - * VBUSY handling. Users will see "waiting for - * busy volume," so they know that something is - * happening. Old cache managers must be able to do - * something reasonable with this, for instance, mark the - * server down. Fortunately, any error code < 0 - * will elicit that behavior. See #1. - * 5. Some combination of the above. I like doing #2 for 10 - * minutes, followed by #4. 3.1b and 3.2 cache managers - * will be fine as long as the restart period is - * not longer than 6.5 minutes, otherwise they may - * return ENODEV to users. 3.3 cache managers will be - * fine for 10 minutes, then will return - * ETIMEDOUT. 3.4 cache managers will just wait - * until the call works or fails definitively. - * NB. The problem with 2,3,4,5 is that old clients won't - * fail over to an alternate read-only replica while this - * server is restarting. 3.4 clients will fail over right away. - */ - if (restartedat.tv_sec == 0) { - /* I'm not really worried about when we restarted, I'm */ - /* just worried about when the first VBUSY was returned. */ - TM_GetTimeOfDay(&restartedat, 0); - return(VBUSY); - } - else { - struct timeval now; - TM_GetTimeOfDay(&now, 0); - if ((now.tv_sec - restartedat.tv_sec) < (11*60)) { - return(VBUSY); - } - else { - return (VRESTARTING); - } - } - } - /* allow read operations on busy volume */ - else if(errorCode==VBUSY && lock==READ_LOCK) { - errorCode=0; - break; - } - else if (errorCode) - return(errorCode); + if ((VanillaUser(client)) && (!(rights & PRSFS_READ))) { + errorCode = EACCES; + goto Bad_GetVolumeStatus; + } + RXGetVolumeStatus(FetchVolStatus, Name, OfflineMsg, Motd, volptr); + +Bad_GetVolumeStatus: + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + ViceLog(2,("SAFS_GetVolumeStatus returns %d\n",errorCode)); + /* next is to guarantee out strings exist for stub */ + if (*Name == 0) {*Name = (char *) malloc(1); **Name = 0;} + if (*Motd == 0) {*Motd = (char *) malloc(1); **Motd = 0;} + if (*OfflineMsg == 0) {*OfflineMsg = (char *) malloc(1); **OfflineMsg = 0;} + CallPostamble(tcon); + +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (errorCode == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); } + FS_UNLOCK } - assert (*volptr); - /* get the vnode */ - *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock); - if (errorCode) - return(errorCode); - if ((*vptr)->disk.uniquifier != fid->Unique) { - VPutVnode(&fileCode, *vptr); - assert(fileCode == 0); - *vptr = 0; - return(VNOVNODE); /* return the right error code, at least */ - } - return(0); -} /*CheckVnode*/ +#endif /* FS_STATS_DETAILED */ + return(errorCode); +} /*SRXAFS_GetVolumeStatus*/ -/* - * This routine returns the ACL associated with the targetptr. If the - * targetptr isn't a directory, we access its parent dir and get the ACL - * thru the parent; in such case the parent's vnode is returned in - * READ_LOCK mode. - */ -static afs_int32 -SetAccessList(Vnode **targetptr, - Volume **volume, - struct acl_accessList **ACL, - int * ACLSize, - Vnode **parent, - AFSFid *Fid, - int Lock) + +afs_int32 SRXAFS_SetVolumeStatus (struct rx_call *acall, + afs_int32 avolid, + AFSStoreVolumeStatus *StoreVolStatus, + char *Name, + char *OfflineMsg, + char *Motd) { - if ((*targetptr)->disk.type == vDirectory) { - *parent = 0; - *ACL = VVnodeACL(*targetptr); - *ACLSize = VAclSize(*targetptr); - return(0); - } - else { - assert(Fid != 0); - while(1) { - VnodeId parentvnode; - int errorCode = 0; - - parentvnode = (*targetptr)->disk.parent; - VPutVnode(&errorCode,*targetptr); - *targetptr = 0; - if (errorCode) return(errorCode); - *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK); - if (errorCode) return(errorCode); - *ACL = VVnodeACL(*parent); - *ACLSize = VAclSize(*parent); - if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0) - return(errorCode); - if ((*targetptr)->disk.parent != parentvnode) { - VPutVnode(&errorCode, *parent); - *parent = 0; - if (errorCode) return(errorCode); - } else - return(0); - } - } + Vnode * targetptr = 0; /* vnode of the new file */ + 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 */ + afs_int32 rights, anyrights; /* rights for this and any user */ + AFSFid dummyFid; + struct rx_connection *tcon = rx_ConnectionOf(acall); +#if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ -} /*SetAccessList*/ + /* + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. + */ + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETVOLUMESTATUS]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ + ViceLog(1,("SAFS_SetVolumeStatus for volume %u\n", avolid)); + if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_SetVolumeStatus; -/* - * Common code that handles the creation of a new file (SAFS_CreateFile and - * SAFS_Symlink) or a new dir (SAFS_MakeDir) - */ -static afs_int32 -Alloc_NewVnode(Vnode *parentptr, - DirHandle *dir, - Volume *volptr, - Vnode **targetptr, - char *Name, - struct AFSFid *OutFid, - int FileType, - int BlocksPreallocatedForVnode) -{ - int errorCode = 0; /* Error code returned back */ - int temp; - Inode inode=0; - Inode nearInode; /* hint for inode allocation in solaris */ + FS_LOCK + AFSCallStats.SetVolumeStatus++, AFSCallStats.TotalCalls++; + FS_UNLOCK - if ((errorCode = AdjustDiskUsage(volptr, BlocksPreallocatedForVnode, - BlocksPreallocatedForVnode))) { - ViceLog(25, ("Insufficient space to allocate %d blocks\n", - BlocksPreallocatedForVnode)); - return(errorCode); + if (avolid == 0) { + errorCode = EINVAL; + goto Bad_SetVolumeStatus; } + dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1; - *targetptr = VAllocVnode(&errorCode, volptr, FileType); - if (errorCode != 0) { - VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode, 0); - return(errorCode); + if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr, + MustBeDIR, &parentwhentargetnotdir, + &client, READ_LOCK, &rights, &anyrights))) + goto Bad_SetVolumeStatus; + + if (readonlyServer) { + errorCode = VREADONLY; + goto Bad_SetVolumeStatus; + } + if (VanillaUser(client)) { + errorCode = EACCES; + goto Bad_SetVolumeStatus; } - OutFid->Volume = V_id(volptr); - OutFid->Vnode = (*targetptr)->vnodeNumber; - OutFid->Unique = (*targetptr)->disk.uniquifier; - nearInode = VN_GET_INO(parentptr); /* parent is also in same vol */ + errorCode = RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name, + OfflineMsg, Motd); - /* create the inode now itself */ - inode = IH_CREATE(V_linkHandle(volptr), V_device(volptr), - VPartitionPath(V_partition(volptr)), nearInode, - V_id(volptr), (*targetptr)->vnodeNumber, - (*targetptr)->disk.uniquifier, 1); + Bad_SetVolumeStatus: + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr); + ViceLog(2,("SAFS_SetVolumeStatus returns %d\n",errorCode)); + CallPostamble(tcon); - /* error in creating inode */ - if (!VALID_INO(inode)) - { - ViceLog(0, ("Volume : %d vnode = %d Failed to create inode: errno = %d\n", - (*targetptr)->volumePtr->header->diskstuff.id, - (*targetptr)->vnodeNumber, - errno)); - VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode,0); - (*targetptr)->delete = 1; /* delete vnode */ - return ENOSPC; +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (errorCode == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK } - VN_SET_INO(*targetptr, inode); - IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode); - /* copy group from parent dir */ - (*targetptr)->disk.group = parentptr->disk.group; +#endif /* FS_STATS_DETAILED */ - if (parentptr->disk.cloned) - { - ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n")); - if ((errorCode = CopyOnWrite(parentptr, volptr))) /* disk full */ - { - ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n")); - /* delete the vnode previously allocated */ - (*targetptr)->delete = 1; - VAdjustDiskUsage(&temp, volptr, - -BlocksPreallocatedForVnode, 0); - IH_REALLYCLOSE((*targetptr)->handle); - if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)) ) - ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n", - volptr->partition->name, - PrintInode(NULL, inode))); - IH_RELEASE((*targetptr)->handle); - - return errorCode; - } - } - - /* add the name to the directory */ - SetDirHandle(dir, parentptr); - if ((errorCode = Create(dir,(char *)Name, OutFid))) { - (*targetptr)->delete = 1; - VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode, 0); - IH_REALLYCLOSE((*targetptr)->handle); - if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr))) - ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n", - volptr->partition->name, - PrintInode(NULL, inode))); - IH_RELEASE((*targetptr)->handle); - return(errorCode); - } - DFlush(); - return(0); + osi_auditU (acall, SetVolumeStatusEvent, errorCode, AUD_LONG, avolid, AUD_STR, Name, AUD_END); + return(errorCode); + +} /*SRXAFS_SetVolumeStatus*/ + +#define DEFAULTVOLUME "root.afs" + +afs_int32 SRXAFS_GetRootVolume (struct rx_call *acall, char **VolumeName) +{ + int fd; + int len; + char *temp; + int errorCode = 0; /* error code */ + struct rx_connection *tcon; +#if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ + + /* + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. + */ + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETROOTVOLUME]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ -} /*Alloc_NewVnode*/ + return FSERR_EOPNOTSUPP; +#ifdef notdef + if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon)) + goto Bad_GetRootVolume; + FS_LOCK + AFSCallStats.GetRootVolume++, AFSCallStats.TotalCalls++; + FS_UNLOCK -/* - * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and - * SAFS_ReleaseLock) - */ -static afs_int32 -HandleLocking(Vnode *targetptr, afs_int32 rights, ViceLockType LockingType) -{ - int Time; /* Used for time */ - int writeVnode = targetptr->changed_oldTime; /* save original status */ + temp = malloc(256); + fd = open(AFSDIR_SERVER_ROOTVOL_FILEPATH, O_RDONLY, 0666); + if (fd <= 0) + strcpy(temp, DEFAULTVOLUME); + else { +#if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV) + lockf(fd, F_LOCK, 0); +#else + flock(fd, LOCK_EX); +#endif + len = read(fd, temp, 256); +#if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV) + lockf(fd, F_ULOCK, 0); +#else + flock(fd, LOCK_UN); +#endif + close(fd); + if (temp[len-1] == '\n') len--; + temp[len] = '\0'; + } + *VolumeName = temp; /* freed by rx server-side stub */ - /* Does the caller has Lock priviledges; root extends locks, however */ - if (LockingType != LockExtend && !(rights & PRSFS_LOCK)) - return(EACCES); - targetptr->changed_oldTime = 1; /* locking doesn't affect any time stamp */ - Time = FT_ApproxTime(); - switch (LockingType) { - case LockRead: - case LockWrite: - if (Time > targetptr->disk.lock.lockTime) - targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount = 0; - Time += AFS_LOCKWAIT; - if (LockingType == LockRead) { - if (targetptr->disk.lock.lockCount >= 0) { - ++(targetptr->disk.lock.lockCount); - targetptr->disk.lock.lockTime = Time; - } else return(EAGAIN); - } else { - if (targetptr->disk.lock.lockCount == 0) { - targetptr->disk.lock.lockCount = -1; - targetptr->disk.lock.lockTime = Time; - } else return(EAGAIN); - } - break; - case LockExtend: - Time += AFS_LOCKWAIT; - if (targetptr->disk.lock.lockCount != 0) - targetptr->disk.lock.lockTime = Time; - else return(EINVAL); - break; - case LockRelease: - if ((--targetptr->disk.lock.lockCount) <= 0) - targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime = 0; - break; - default: - targetptr->changed_oldTime = writeVnode; /* restore old status */ - ViceLog(0, ("Illegal Locking type %d\n", LockingType)); +Bad_GetRootVolume: + CallPostamble(tcon); + +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (errorCode == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK } - return(0); -} /*HandleLocking*/ +#endif /* FS_STATS_DETAILED */ -/* - * 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 - * in rights and anyrights, respectively - */ -static afs_int32 -GetRights (struct client *client, - struct acl_accessList *ACL, - afs_int32 *rights, - afs_int32 *anyrights) + return(errorCode); +#endif /* notdef */ + +} /*SRXAFS_GetRootVolume*/ + + +/* still works because a struct CBS is the same as a struct AFSOpaque */ +afs_int32 SRXAFS_CheckToken (struct rx_call *acall, + afs_int32 AfsId, + struct AFSOpaque *Token) { - extern prlist SystemAnyUserCPS; - afs_int32 hrights = 0; - int code; + afs_int32 code; + struct rx_connection *tcon; +#if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ - if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) { + /* + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. + */ + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CHECKTOKEN]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ - ViceLog(0,("CheckRights failed\n")); - *anyrights = 0; - } - *rights = 0; - acl_CheckRights(ACL, &client->CPS, rights); + if ((code = CallPreamble(acall, ACTIVECALL, &tcon))) + goto Bad_CheckToken; - /* wait if somebody else is already doing the getCPS call */ - H_LOCK - while ( client->host->hostFlags & HCPS_INPROGRESS ) - { - client->host->hostFlags |= HCPS_WAITING; /* I am waiting */ -#ifdef AFS_PTHREAD_ENV - pthread_cond_wait(&client->host->cond, &host_glock_mutex); -#else /* AFS_PTHREAD_ENV */ - if ((code=LWP_WaitProcess( &(client->host->hostFlags))) !=LWP_SUCCESS) - ViceLog(0, ("LWP_WaitProcess returned %d\n", code)); -#endif /* AFS_PTHREAD_ENV */ + code = FSERR_ECONNREFUSED; + +Bad_CheckToken: + CallPostamble(tcon); + +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + if (code == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK } - if (client->host->hcps.prlist_len && !client->host->hcps.prlist_val) { - ViceLog(0,("CheckRights: len=%d, for host=0x%x\n", client->host->hcps.prlist_len, client->host->host)); - } else - 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)) - *rights |= implicitAdminRights; - *rights |= hrights; - *anyrights |= hrights; +#endif /* FS_STATS_DETAILED */ - return(0); + return code; -} /*GetRights*/ +} /*SRXAFS_CheckToken*/ +afs_int32 SRXAFS_GetTime (struct rx_call *acall, + afs_uint32 *Seconds, + afs_uint32 *USeconds) +{ + afs_int32 code; + struct rx_connection *tcon; + struct timeval tpl; +#if FS_STATS_DETAILED + struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ + struct timeval opStartTime, + opStopTime; /* Start/stop times for RPC op*/ + struct timeval elapsedTime; /* Transfer time */ -/* Checks if caller has the proper AFS and Unix (WRITE) access permission to the target directory; Prfs_Mode refers to the AFS Mode operation while rights contains the caller's access permissions to the directory. */ + /* + * Set our stats pointer, remember when the RPC operation started, and + * tally the operation. + */ + opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETTIME]); + FS_LOCK + (opP->numOps)++; + FS_UNLOCK + TM_GetTimeOfDay(&opStartTime, 0); +#endif /* FS_STATS_DETAILED */ -static afs_int32 -CheckWriteMode(Vnode *targetptr, afs_int32 rights, int Prfs_Mode) -{ - if (readonlyServer) - return(VREADONLY); - if (!(rights & Prfs_Mode)) - return(EACCES); - if ((targetptr->disk.type != vDirectory) && (!(targetptr->disk.modeBits & OWNERWRITE))) - return(EACCES); - return(0); -} + if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon))) + goto Bad_GetTime; -/* In our current implementation, each successive data store (new file - * data version) creates a new inode. This function creates the new - * inode, copies the old inode's contents to the new one, remove the old - * inode (i.e. decrement inode count -- if it's currently used the delete - * will be delayed), and modify some fields (i.e. vnode's - * disk.inodeNumber and cloned) - */ -#define COPYBUFFSIZE 8192 -static int CopyOnWrite(Vnode *targetptr, Volume *volptr) -{ - Inode ino, nearInode; - int rdlen; - int wrlen; - register int size, length; - int ifd, ofd; - char *buff; - int rc; /* return code */ - IHandle_t *newH; /* Use until finished copying, then cp to vnode.*/ - FdHandle_t *targFdP; /* Source Inode file handle */ - FdHandle_t *newFdP; /* Dest Inode file handle */ + FS_LOCK + AFSCallStats.GetTime++, AFSCallStats.TotalCalls++; + FS_UNLOCK - if (targetptr->disk.type == vDirectory) DFlush(); /* just in case? */ + TM_GetTimeOfDay(&tpl, 0); + *Seconds = tpl.tv_sec; + *USeconds = tpl.tv_usec; - size = targetptr->disk.length; - buff = (char *)malloc(COPYBUFFSIZE); - if (buff == NULL) { - return EIO; - } + ViceLog(2, ("SAFS_GetTime returns %d, %d\n", *Seconds, *USeconds)); + +Bad_GetTime: + CallPostamble(tcon); - ino = VN_GET_INO(targetptr); - assert(VALID_INO(ino)); - targFdP = IH_OPEN(targetptr->handle); - if (targFdP == NULL) { - rc = errno; - ViceLog(0, ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n", targetptr->vnodeNumber, V_id(volptr), rc)); - free(buff); - VTakeOffline (volptr); - return rc; +#if FS_STATS_DETAILED + TM_GetTimeOfDay(&opStopTime, 0); + fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime); + if (code == 0) { + FS_LOCK + (opP->numSuccesses)++; + fs_stats_AddTo((opP->sumTime), elapsedTime); + fs_stats_SquareAddTo((opP->sqrTime), elapsedTime); + if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) { + fs_stats_TimeAssign((opP->minTime), elapsedTime); + } + if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) { + fs_stats_TimeAssign((opP->maxTime), elapsedTime); + } + FS_UNLOCK } - nearInode = VN_GET_INO(targetptr); - ino = IH_CREATE(V_linkHandle(volptr), V_device(volptr), - VPartitionPath(V_partition(volptr)),nearInode, V_id(volptr), - targetptr->vnodeNumber, targetptr->disk.uniquifier, - (int)targetptr->disk.dataVersion); - if (!VALID_INO(ino)) - { - ViceLog(0,("CopyOnWrite failed: Partition %s that contains volume %u may be out of free inodes(errno = %d)\n", volptr->partition->name, V_id(volptr), errno)); - FDH_CLOSE(targFdP); - free(buff); - return ENOSPC; - } - IH_INIT(newH, V_device(volptr), V_id(volptr), ino); - newFdP = IH_OPEN(newH); - assert(newFdP != NULL); +#endif /* FS_STATS_DETAILED */ - while(size > 0) { - if (size > COPYBUFFSIZE) { /* more than a buffer */ - length = COPYBUFFSIZE; - size -= COPYBUFFSIZE; - } else { - length = size; - size = 0; - } - rdlen = FDH_READ(targFdP, buff, length); - if (rdlen == length) - wrlen = FDH_WRITE(newFdP, buff, length); - else - wrlen = 0; - /* Callers of this function are not prepared to recover - * from error that put the filesystem in an inconsistent - * state. Make sure that we force the volume off-line if - * we some error other than ENOSPC - 4.29.99) - * - * In case we are unable to write the required bytes, and the - * error code indicates that the disk is full, we roll-back to - * the initial state. - */ - if((rdlen != length) || (wrlen != length)) - if ( (wrlen < 0) && (errno == ENOSPC) ) /* disk full */ - { - ViceLog(0,("CopyOnWrite failed: Partition %s containing volume %u is full\n", - volptr->partition->name, V_id(volptr))); - /* remove destination inode which was partially copied till now*/ - FDH_REALLYCLOSE(newFdP); - IH_RELEASE(newH); - FDH_REALLYCLOSE(targFdP); - rc = IH_DEC(V_linkHandle(volptr), ino, - V_parentId(volptr)); - if (!rc ) { - ViceLog(0,("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n", - rc, V_id(volptr), - volptr->partition->name)); - VTakeOffline (volptr); - } - free(buff); - return ENOSPC; - } - else { - ViceLog(0,("CopyOnWrite failed: volume %u in partition %s (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n", - V_id(volptr), volptr->partition->name, length, - rdlen, wrlen, errno)); -#ifdef FAST_RESTART /* if running in no-salvage, don't core the server */ - ViceLog(0,("CopyOnWrite failed: taking volume offline\n")); -#else /* Avoid further corruption and try to get a core. */ - assert(0); -#endif - /* Decrement this inode so salvager doesn't find it. */ - FDH_REALLYCLOSE(newFdP); - IH_RELEASE(newH); - FDH_REALLYCLOSE(targFdP); - rc = IH_DEC(V_linkHandle(volptr), ino, - V_parentId(volptr)); - free(buff); - VTakeOffline (volptr); - return EIO; - } -#ifndef AFS_PTHREAD_ENV - IOMGR_Poll(); -#endif /* !AFS_PTHREAD_ENV */ - } - FDH_REALLYCLOSE(targFdP); - rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr), - V_parentId(volptr)) ; - assert(!rc); - IH_RELEASE(targetptr->handle); + return code; - rc = FDH_SYNC(newFdP); - assert(rc == 0); - FDH_CLOSE(newFdP); - targetptr->handle = newH; - VN_SET_INO(targetptr, ino); - targetptr->disk.cloned = 0; - /* Internal change to vnode, no user level change to volume - def 5445 */ - targetptr->changed_oldTime = 1; - free(buff); - return 0; /* success */ -} /*CopyOnWrite*/ +} /*SRXAFS_GetTime*/ /* - * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not - * a System:Administrator) + * FetchData_RXStyle + * + * Purpose: + * Implement a client's data fetch using Rx. + * + * Arguments: + * volptr : Ptr to the given volume's info. + * targetptr : Pointer to the vnode involved. + * Call : Ptr to the Rx call involved. + * Pos : Offset within the file. + * Len : Length in bytes to read; this value is bogus! + * if FS_STATS_DETAILED + * a_bytesToFetchP : Set to the number of bytes to be fetched from + * the File Server. + * a_bytesFetchedP : Set to the actual number of bytes fetched from + * the File Server. + * endif */ -static afs_int32 -VanillaUser(struct client *client) + +afs_int32 +FetchData_RXStyle(Volume *volptr, + Vnode *targetptr, + register struct rx_call *Call, + afs_int32 Pos, + afs_int32 Len, + afs_int32 Int64Mode, +#if FS_STATS_DETAILED + afs_int32 *a_bytesToFetchP, + afs_int32 *a_bytesFetchedP +#endif /* FS_STATS_DETAILED */ + ) { - if (acl_IsAMember(SystemId, &client->CPS)) - return(0); /* not a system administrator, then you're "vanilla" */ - return(1); + struct timeval StartTime, StopTime; /* used to calculate file transfer rates */ + int errorCode = 0; /* Returned error code to caller */ + int code; + IHandle_t *ihP; + FdHandle_t *fdP; +#ifdef AFS_NT40_ENV + register char *tbuffer; +#else /* AFS_NT40_ENV */ + struct iovec tiov[RX_MAXIOVECS]; + int tnio; +#endif /* AFS_NT40_ENV */ + afs_int32 tlen; + afs_int32 optSize; + struct stat tstat; +#ifdef AFS_AIX_ENV + struct statfs tstatfs; +#endif + +#if FS_STATS_DETAILED + /* + * Initialize the byte count arguments. + */ + (*a_bytesToFetchP) = 0; + (*a_bytesFetchedP) = 0; +#endif /* FS_STATS_DETAILED */ + + if (!VN_GET_INO(targetptr)) { + /* + * This is used for newly created files; we simply send 0 bytes + * back to make the cache manager happy... + */ + tlen = htonl(0); + if (Int64Mode) + rx_Write(Call, (char *)&tlen, sizeof(afs_int32)); /* send 0-length */ + rx_Write(Call, (char *)&tlen, sizeof(afs_int32)); /* send 0-length */ + return (0); + } + TM_GetTimeOfDay(&StartTime, 0); + ihP = targetptr->handle; + fdP = IH_OPEN(ihP); + if (fdP == NULL) return EIO; + optSize = AFSV_BUFFERSIZE; + tlen = FDH_SIZE(fdP); + if (tlen < 0) { + FDH_CLOSE(fdP); + return EIO; + } + + if (Pos + Len > tlen) Len = tlen - Pos; /* get length we should send */ + FDH_SEEK(fdP, Pos, 0); + tlen = htonl(Len); + if (Int64Mode) { + afs_int32 zero = 0; + rx_Write(Call, (char *)&zero, sizeof(afs_int32)); /* High order bits */ + } + rx_Write(Call, (char *)&tlen, sizeof(afs_int32)); /* send length on fetch */ +#if FS_STATS_DETAILED + (*a_bytesToFetchP) = Len; +#endif /* FS_STATS_DETAILED */ +#ifdef AFS_NT40_ENV + tbuffer = AllocSendBuffer(); +#endif /* AFS_NT40_ENV */ + while (Len > 0) { + if (Len > optSize) tlen = optSize; + else tlen = Len; +#ifdef AFS_NT40_ENV + errorCode = FDH_READ(fdP, tbuffer, tlen); + if (errorCode != tlen) { + FDH_CLOSE(fdP); + FreeSendBuffer((struct afs_buffer *) tbuffer); + return EIO; + } + errorCode = rx_Write(Call, tbuffer, tlen); +#else /* AFS_NT40_ENV */ + errorCode = rx_WritevAlloc(Call, tiov, &tnio, RX_MAXIOVECS, tlen); + if (errorCode <= 0) { + FDH_CLOSE(fdP); + return EIO; + } + tlen = errorCode; + errorCode = FDH_READV(fdP, tiov, tnio); + if (errorCode != tlen) { + FDH_CLOSE(fdP); + return EIO; + } + errorCode = rx_Writev(Call, tiov, tnio, tlen); +#endif /* AFS_NT40_ENV */ +#if FS_STATS_DETAILED + /* + * Bump the number of bytes actually sent by the number from this + * latest iteration + */ + (*a_bytesFetchedP) += errorCode; +#endif /* FS_STATS_DETAILED */ + if (errorCode != tlen) { + FDH_CLOSE(fdP); +#ifdef AFS_NT40_ENV + FreeSendBuffer((struct afs_buffer *) tbuffer); +#endif /* AFS_NT40_ENV */ + return -31; + } + Len -= tlen; + } +#ifdef AFS_NT40_ENV + FreeSendBuffer((struct afs_buffer *) tbuffer); +#endif /* AFS_NT40_ENV */ + FDH_CLOSE(fdP); + TM_GetTimeOfDay(&StopTime, 0); -} /*VanillaUser*/ + /* Adjust all Fetch Data related stats */ + FS_LOCK + if (AFSCallStats.TotalFetchedBytes > 2000000000) /* Reset if over 2 billion */ + AFSCallStats.TotalFetchedBytes = AFSCallStats.AccumFetchTime = 0; + AFSCallStats.AccumFetchTime += ((StopTime.tv_sec - StartTime.tv_sec) * 1000) + + ((StopTime.tv_usec - StartTime.tv_usec) / 1000); + AFSCallStats.TotalFetchedBytes += targetptr->disk.length; + AFSCallStats.FetchSize1++; + if (targetptr->disk.length < SIZE2) + AFSCallStats.FetchSize2++; + else if (targetptr->disk.length < SIZE3) + AFSCallStats.FetchSize3++; + else if (targetptr->disk.length < SIZE4) + AFSCallStats.FetchSize4++; + else + AFSCallStats.FetchSize5++; + FS_UNLOCK + return (0); +} /*FetchData_RXStyle*/ -/* - * Adjusts (Subtract) "length" number of blocks from the volume's disk - * allocation; if some error occured (exceeded volume quota or partition - * was full, or whatever), it frees the space back and returns the code. - * We usually pre-adjust the volume space to make sure that there's - * enough space before consuming some. - */ -static afs_int32 -AdjustDiskUsage(Volume *volptr, afs_int32 length, afs_int32 checkLength) +static int GetLinkCountAndSize(Volume *vp, FdHandle_t *fdP, int *lc, int *size) { - int rc; - int nc; +#ifdef AFS_NAMEI_ENV + FdHandle_t *lhp; + lhp = IH_OPEN(V_linkHandle(vp)); + if (!lhp) + return EIO; +#ifdef AFS_NT40_ENV + *lc = nt_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0); +#else + *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0); +#endif + FDH_CLOSE(lhp); + if (*lc < 0 ) + return -1; + *size = OS_SIZE(fdP->fd_fd); + return (*size == -1) ? -1 : 0; +#else + struct stat status; - VAdjustDiskUsage(&rc, volptr, length, checkLength); - if (rc) { - VAdjustDiskUsage(&nc, volptr, -length, 0); - if (rc == VOVERQUOTA) { - ViceLog(2,("Volume %u (%s) is full\n", - V_id(volptr), V_name(volptr))); - return(rc); - } - if (rc == VDISKFULL) { - ViceLog(0,("Partition %s that contains volume %u is full\n", - volptr->partition->name, V_id(volptr))); - return(rc); - } - ViceLog(0,("Got error return %d from VAdjustDiskUsage\n",rc)); - return(rc); + if (fstat(fdP->fd_fd, &status)<0) { + return -1; } - return(0); -} /*AdjustDiskUsage*/ + *lc = GetLinkCount(vp, &status); + *size = status.st_size; + return 0; +#endif +} /* - * If some flags (i.e. min or max quota) are set, the volume's in disk - * label is updated; Name, OfflineMsg, and Motd are also reflected in the - * update, if applicable. + * StoreData_RXStyle + * + * Purpose: + * Implement a client's data store using Rx. + * + * Arguments: + * volptr : Ptr to the given volume's info. + * targetptr : Pointer to the vnode involved. + * Call : Ptr to the Rx call involved. + * Pos : Offset within the file. + * Len : Length in bytes to store; this value is bogus! + * if FS_STATS_DETAILED + * a_bytesToStoreP : Set to the number of bytes to be stored to + * the File Server. + * a_bytesStoredP : Set to the actual number of bytes stored to + * the File Server. + * endif */ -static afs_int32 -RXUpdate_VolumeStatus(Volume *volptr, AFSStoreVolumeStatus* StoreVolStatus, - char *Name, char *OfflineMsg, char *Motd) +afs_int32 +StoreData_RXStyle(Volume *volptr, + Vnode *targetptr, + struct AFSFid *Fid, + struct client *client, + register struct rx_call *Call, + afs_uint32 Pos, + afs_uint32 Length, + afs_uint32 FileLength, + int sync, +#if FS_STATS_DETAILED + afs_int32 *a_bytesToStoreP, + afs_int32 *a_bytesStoredP +#endif /* FS_STATS_DETAILED */ + ) { - Error errorCode = 0; + int bytesTransfered; /* number of bytes actually transfered */ + struct timeval StartTime, StopTime; /* Used to measure how long the store takes */ + int errorCode = 0; /* Returned error code to caller */ +#ifdef AFS_NT40_ENV + register char *tbuffer; /* data copying buffer */ +#else /* AFS_NT40_ENV */ + struct iovec tiov[RX_MAXIOVECS]; /* no data copying with iovec */ + int tnio; /* temp for iovec size */ +#endif /* AFS_NT40_ENV */ + int tlen; /* temp for xfr length */ + Inode tinode; /* inode for I/O */ + afs_int32 optSize; /* optimal transfer size */ + int DataLength; /* size of inode */ + afs_int32 TruncatedLength; /* size after ftruncate */ + afs_uint32 NewLength; /* size after this store completes */ + afs_int32 adjustSize; /* bytes to call VAdjust... with */ + int linkCount; /* link count on inode */ + int code; + FdHandle_t *fdP; + struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ - if (StoreVolStatus->Mask & AFS_SETMINQUOTA) - V_minquota(volptr) = StoreVolStatus->MinQuota; - if (StoreVolStatus->Mask & AFS_SETMAXQUOTA) - V_maxquota(volptr) = StoreVolStatus->MaxQuota; - if (strlen(OfflineMsg) > 0) { - strcpy(V_offlineMessage(volptr), OfflineMsg); - } - if (strlen(Name) > 0) { - strcpy(V_name(volptr), Name); - } -#if TRANSARC_VOL_STATS +#if FS_STATS_DETAILED /* - * We don't overwrite the motd field, since it's now being used - * for stats + * Initialize the byte count arguments. */ -#else - if (strlen(Motd) > 0) { - strcpy(V_motd(volptr), Motd); - } + (*a_bytesToStoreP) = 0; + (*a_bytesStoredP) = 0; #endif /* FS_STATS_DETAILED */ - VUpdateVolume(&errorCode, volptr); - return(errorCode); - -} /*RXUpdate_VolumeStatus*/ - - -/* old interface */ -static afs_int32 -Update_VolumeStatus(Volume *volptr, VolumeStatus *StoreVolStatus, - struct BBS *Name, struct BBS *OfflineMsg, - struct BBS *Motd) -{ - Error errorCode = 0; - if (StoreVolStatus->MinQuota > -1) - V_minquota(volptr) = StoreVolStatus->MinQuota; - if (StoreVolStatus->MaxQuota > -1) - V_maxquota(volptr) = StoreVolStatus->MaxQuota; - if (OfflineMsg->SeqLen > 1) - strcpy(V_offlineMessage(volptr), OfflineMsg->SeqBody); - if (Name->SeqLen > 1) - strcpy(V_name(volptr), Name->SeqBody); -#if TRANSARC_VOL_STATS /* - * We don't overwrite the motd field, since it's now being used - * for stats + * We break the callbacks here so that the following signal will not + * leave a window. */ -#else - if (Motd->SeqLen > 1) - strcpy(V_motd(volptr), Motd->SeqBody); -#endif /* FS_STATS_DETAILED */ - VUpdateVolume(&errorCode, volptr); - return(errorCode); - -} /*Update_VolumeStatus*/ - + BreakCallBack(client->host, Fid, 0); -/* - * Get internal volume-related statistics from the Volume disk label - * structure and put it into the VolumeStatus structure, status; it's - * used by both SAFS_GetVolumeStatus and SAFS_SetVolumeStatus to return - * the volume status to the caller. - */ -static afs_int32 -GetVolumeStatus(VolumeStatus *status, struct BBS *name, struct BBS *offMsg, - struct BBS *motd, Volume *volptr) -{ - status->Vid = V_id(volptr); - status->ParentId = V_parentId(volptr); - status->Online = V_inUse(volptr); - status->InService = V_inService(volptr); - status->Blessed = V_blessed(volptr); - status->NeedsSalvage = V_needsSalvaged(volptr); - if (VolumeWriteable(volptr)) - status->Type = ReadWrite; - else - status->Type = ReadOnly; - status->MinQuota = V_minquota(volptr); - status->MaxQuota = V_maxquota(volptr); - status->BlocksInUse = V_diskused(volptr); - status->PartBlocksAvail = volptr->partition->free; - status->PartMaxBlocks = volptr->partition->totalUsable; - strncpy(name->SeqBody, V_name(volptr), (int)name->MaxSeqLen); - name->SeqLen = strlen(V_name(volptr)) + 1; - if (name->SeqLen > name->MaxSeqLen) name->SeqLen = name -> MaxSeqLen; - strncpy(offMsg->SeqBody, V_offlineMessage(volptr), (int)name->MaxSeqLen); - offMsg->SeqLen = strlen(V_offlineMessage(volptr)) + 1; - if (offMsg->SeqLen > offMsg->MaxSeqLen) - offMsg->SeqLen = offMsg -> MaxSeqLen; -#ifdef notdef - /*Don't do anything with the motd field*/ - strncpy(motd->SeqBody, nullString, (int)offMsg->MaxSeqLen); - motd->SeqLen = strlen(nullString) + 1; -#endif - if (motd->SeqLen > motd->MaxSeqLen) - motd->SeqLen = motd -> MaxSeqLen; + if (Pos == -1 || VN_GET_INO(targetptr) == 0) { + /* the inode should have been created in Alloc_NewVnode */ + logHostAddr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(Call))); + ViceLog(0, ("StoreData_RXStyle : Inode non-existent Fid = %u.%d.%d, inode = %d, Pos %d Host %s\n", + Fid->Volume, Fid->Vnode, Fid->Unique, + VN_GET_INO(targetptr), Pos, inet_ntoa(logHostAddr) )); + return ENOENT; /* is this proper error code? */ + } + else { + /* + * See if the file has several links (from other volumes). If it + * does, then we have to make a copy before changing it to avoid + *changing read-only clones of this dude + */ + ViceLog(25, ("StoreData_RXStyle : Opening inode %s\n", + PrintInode(NULL, VN_GET_INO(targetptr)))); + fdP = IH_OPEN(targetptr->handle); + if (fdP == NULL) + return ENOENT; + if (GetLinkCountAndSize(volptr, fdP, &linkCount, + &DataLength)<0) { + FDH_CLOSE(fdP); + return EIO; + } + + if (linkCount != 1) { + afs_uint32 size; + ViceLog(25, ("StoreData_RXStyle : inode %s has more than onelink\n", + PrintInode(NULL, VN_GET_INO(targetptr)))); + /* other volumes share this data, better copy it first */ -} /*GetVolumeStatus*/ + /* Adjust the disk block count by the creation of the new inode. + * We call the special VDiskUsage so we don't adjust the volume's + * quota since we don't want to penalyze the user for afs's internal + * mechanisms (i.e. copy on write overhead.) Also the right size + * of the disk will be recorded... + */ + FDH_CLOSE(fdP); + size = targetptr->disk.length; + volptr->partition->flags &= ~PART_DONTUPDATE; + VSetPartitionDiskUsage(volptr->partition); + volptr->partition->flags |= PART_DONTUPDATE; + if ((errorCode = VDiskUsage(volptr, nBlocks(size)))) { + volptr->partition->flags &= ~PART_DONTUPDATE; + return(errorCode); + } -static afs_int32 -RXGetVolumeStatus(AFSFetchVolumeStatus *status, char **name, char **offMsg, - char **motd, Volume *volptr) -{ - int temp; + ViceLog(25, ("StoreData : calling CopyOnWrite on target dir\n")); + if ((errorCode = CopyOnWrite(targetptr, volptr))) + { + ViceLog(25, ("StoreData : CopyOnWrite failed\n")); + volptr->partition->flags &= ~PART_DONTUPDATE; + return (errorCode); + } + volptr->partition->flags &= ~PART_DONTUPDATE; + VSetPartitionDiskUsage(volptr->partition); + fdP = IH_OPEN(targetptr->handle); + if (fdP == NULL) { + ViceLog(25, ("StoreData : Reopen after CopyOnWrite failed\n")); + return ENOENT; + } + } + tinode = VN_GET_INO(targetptr); + } + assert(VALID_INO(tinode)); - status->Vid = V_id(volptr); - status->ParentId = V_parentId(volptr); - status->Online = V_inUse(volptr); - status->InService = V_inService(volptr); - status->Blessed = V_blessed(volptr); - status->NeedsSalvage = V_needsSalvaged(volptr); - if (VolumeWriteable(volptr)) - status->Type = ReadWrite; - else - status->Type = ReadOnly; - status->MinQuota = V_minquota(volptr); - status->MaxQuota = V_maxquota(volptr); - status->BlocksInUse = V_diskused(volptr); - status->PartBlocksAvail = volptr->partition->free; - status->PartMaxBlocks = volptr->partition->totalUsable; + /* compute new file length */ + NewLength = DataLength; + if (FileLength < NewLength) + /* simulate truncate */ + NewLength = FileLength; + TruncatedLength = NewLength; /* remember length after possible ftruncate */ + if (Pos + Length > NewLength) + NewLength = Pos+Length; /* and write */ - /* now allocate and copy these things; they're freed by the RXGEN stub */ - temp = strlen(V_name(volptr)) + 1; - *name = malloc(temp); - strcpy(*name, V_name(volptr)); - temp = strlen(V_offlineMessage(volptr)) + 1; - *offMsg = malloc(temp); - strcpy(*offMsg, V_offlineMessage(volptr)); -#if TRANSARC_VOL_STATS - *motd = malloc(1); - strcpy(*motd, nullString); -#else - temp = strlen(V_motd(volptr)) + 1; - *motd = malloc(temp); - strcpy(*motd, V_motd(volptr)); -#endif /* FS_STATS_DETAILED */ + /* adjust the disk block count by the difference in the files */ + adjustSize = (int) (nBlocks(NewLength) - nBlocks(targetptr->disk.length)); + if((errorCode = AdjustDiskUsage(volptr, adjustSize, + adjustSize - SpareComp(volptr)))) { + FDH_CLOSE(fdP); + return(errorCode); + } -} /*RXGetVolumeStatus*/ + /* can signal cache manager to proceed from close now */ + /* this bit means that the locks are set and protections are OK */ + rx_SetLocalStatus(Call, 1); + TM_GetTimeOfDay(&StartTime, 0); -static afs_int32 -FileNameOK(register char *aname) -{ - register afs_int32 i, tc; - i = strlen(aname); - if (i >= 4) { - /* watch for @sys on the right */ - if (strcmp(aname+i-4, "@sys") == 0) return 0; + optSize = AFSV_BUFFERSIZE; + + /* truncate the file iff it needs it (ftruncate is slow even when its a noop) */ + if (FileLength < DataLength) FDH_TRUNC(fdP, FileLength); + if (Pos > 0) FDH_SEEK(fdP, Pos, 0); + bytesTransfered = 0; +#ifdef AFS_NT40_ENV + tbuffer = AllocSendBuffer(); +#endif /* AFS_NT40_ENV */ + /* if length == 0, the loop below isn't going to do anything, including + * extend the length of the inode, which it must do, since the file system + * assumes that the inode length == vnode's file length. So, we extend + * the file length manually if need be. Note that if file is bigger than + * Pos+(Length==0), we dont' have to do anything, and certainly shouldn't + * do what we're going to do below. + */ + if (Length == 0 && Pos > TruncatedLength) { + /* Set the file's length; we've already done an lseek to the right + * spot above. + */ + errorCode = FDH_WRITE(fdP, &tlen, 1); + if (errorCode != 1) goto done; + errorCode = FDH_TRUNC(fdP, Pos); } - while ((tc = *aname++)) { - if (tc == '/') return 0; /* very bad character to encounter */ + else { + /* have some data to copy */ +#if FS_STATS_DETAILED + (*a_bytesToStoreP) = Length; +#endif /* FS_STATS_DETAILED */ + while (1) { + if (bytesTransfered >= Length) { + errorCode = 0; + break; + } + tlen = Length - bytesTransfered; /* how much more to do */ + if (tlen > optSize) tlen = optSize; /* bound by buffer size */ +#ifdef AFS_NT40_ENV + errorCode = rx_Read(Call, tbuffer, tlen); +#else /* AFS_NT40_ENV */ + errorCode = rx_Readv(Call, tiov, &tnio, RX_MAXIOVECS, tlen); +#endif /* AFS_NT40_ENV */ +#if FS_STATS_DETAILED + (*a_bytesStoredP) += errorCode; +#endif /* FS_STATS_DETAILED */ + if (errorCode <= 0) { + errorCode = -32; + break; + } + tlen = errorCode; +#ifdef AFS_NT40_ENV + errorCode = FDH_WRITE(fdP, tbuffer, tlen); +#else /* AFS_NT40_ENV */ + errorCode = FDH_WRITEV(fdP, tiov, tnio); +#endif /* AFS_NT40_ENV */ + if (errorCode != tlen) { + errorCode = VDISKFULL; + break; + } + bytesTransfered += tlen; + } } - return 1; /* file name is ok */ - -} /*FileNameOK*/ + done: +#ifdef AFS_NT40_ENV + FreeSendBuffer((struct afs_buffer *) tbuffer); +#endif /* AFS_NT40_ENV */ + if (sync) { + FDH_SYNC(fdP); + } + if (errorCode) { + /* something went wrong: adjust size and return */ + targetptr->disk.length = FDH_SIZE(fdP); /* set new file size. */ + /* changed_newTime is tested in StoreData to detemine if we + * need to update the target vnode. + */ + targetptr->changed_newTime = 1; + FDH_CLOSE(fdP); + /* set disk usage to be correct */ + VAdjustDiskUsage(&errorCode, volptr, + (int)(nBlocks(targetptr->disk.length) + - nBlocks(NewLength)), 0); + return errorCode; + } + FDH_CLOSE(fdP); + TM_GetTimeOfDay(&StopTime, 0); -/* Debugging tool to print Volume Statu's contents */ -static void -PrintVolumeStatus(VolumeStatus *status) -{ - ViceLog(5,("Volume header contains:\n")); - ViceLog(5,("Vid = %u, Parent = %u, Online = %d, InService = %d, Blessed = %d, NeedsSalvage = %d\n", - status->Vid, status->ParentId, status->Online, status->InService, - status->Blessed, status->NeedsSalvage)); - ViceLog(5,("MinQuota = %d, MaxQuota = %d\n", status->MinQuota, status->MaxQuota)); - ViceLog(5,("Type = %d, BlocksInUse = %d, PartBlocksAvail = %d, PartMaxBlocks = %d\n", - status->Type, status->BlocksInUse, status->PartBlocksAvail, status->PartMaxBlocks)); + targetptr->disk.length = NewLength; -} /*PrintVolumeStatus*/ + /* Update all StoreData related stats */ + FS_LOCK + if (AFSCallStats.TotalStoredBytes > 2000000000) /* reset if over 2 billion */ + AFSCallStats.TotalStoredBytes = AFSCallStats.AccumStoreTime = 0; + AFSCallStats.StoreSize1++; /* Piggybacked data */ + if (targetptr->disk.length < SIZE2) + AFSCallStats.StoreSize2++; + else if (targetptr->disk.length < SIZE3) + AFSCallStats.StoreSize3++; + else if (targetptr->disk.length < SIZE4) + AFSCallStats.StoreSize4++; + else + AFSCallStats.StoreSize5++; + FS_UNLOCK + return(errorCode); +} /*StoreData_RXStyle*/ -/* - * This variant of symlink is expressly to support the AFS/DFS translator - * and is not supported by the AFS fileserver. We just return EINVAL. - * The cache manager should not generate this call to an AFS cache manager. - */ -afs_int32 SRXAFS_DFSSymlink (struct rx_call *acall, - struct AFSFid *DirFid, - char *Name, - char *LinkContents, - struct AFSStoreStatus *InStatus, - struct AFSFid *OutFid, - struct AFSFetchStatus *OutFidStatus, - struct AFSFetchStatus *OutDirStatus, - struct AFSCallBack *CallBack, - struct AFSVolSync *Sync) -{ - return EINVAL; -} -afs_int32 SRXAFS_ResidencyCmd (struct rx_call *acall, struct AFSFid *Fid, - struct ResidencyCmdInputs *Inputs, - struct ResidencyCmdOutputs *Outputs) -{ - return EINVAL; -} diff --git a/src/viced/host.c b/src/viced/host.c index f464c89cf..5edd3cf15 100644 --- a/src/viced/host.c +++ b/src/viced/host.c @@ -363,10 +363,7 @@ int h_NBLock_r(register struct host *host) * As advertised. *------------------------------------------------------------------------*/ -static char h_AddrInSameNetwork(a_targetAddr, a_candAddr) - afs_uint32 a_targetAddr; - afs_uint32 a_candAddr; - +static char h_AddrInSameNetwork(afs_uint32 a_targetAddr, afs_uint32 a_candAddr) { /*h_AddrInSameNetwork*/ afs_uint32 targetNet; @@ -420,9 +417,8 @@ static char h_AddrInSameNetwork(a_targetAddr, a_candAddr) -h_gethostcps_r(host,now) - register struct host *host; - register afs_int32 now; +void +h_gethostcps_r(register struct host *host, register afs_int32 now) { register int code; int slept=0, held; @@ -532,8 +528,7 @@ return; */ #define DEF_ROPCONS 2115 -struct host *h_Alloc(r_con) - register struct rx_connection *r_con; +struct host *h_Alloc(register struct rx_connection *r_con) { struct host *retVal; H_LOCK @@ -542,9 +537,7 @@ struct host *h_Alloc(r_con) return retVal; } -struct host *h_Alloc_r(r_con) - register struct rx_connection *r_con; - +struct host *h_Alloc_r(register struct rx_connection *r_con) { register int code; struct servent *serverentry; @@ -890,6 +883,23 @@ void h_Enumerate_r(int (*proc)(), struct host* enumstart, char *param) } } /*h_Enumerate_r*/ +/* inserts a new HashChain structure corresponding to this UUID */ +void hashInsertUuid_r(struct afsUUID *uuid, struct host* host) +{ + int index; + struct h_hashChain* chain; + + /* hash into proper bucket */ + index = h_UuidHashIndex(uuid); + + /* insert into beginning of list for this bucket */ + chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain)); + assert(chain); + chain->hostPtr = host; + chain->next = hostUuidHashTable[index]; + hostUuidHashTable[index] = chain; +} + /* Host is returned held */ struct host *h_GetHost_r(struct rx_connection *tcon) { @@ -2035,6 +2045,25 @@ initInterfaceAddr_r(struct host *host, struct interfaceAddr *interf) return 0; } +/* inserts a new HashChain structure corresponding to this address */ +void hashInsert_r(afs_int32 addr, struct host* host) +{ + int index; + struct h_hashChain* chain; + + /* hash into proper bucket */ + index = h_HashIndex(addr); + + /* insert into beginning of list for this bucket */ + chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain)); + assert(chain); + chain->hostPtr = host; + chain->next = hostHashTable[index]; + chain->addr = addr; + hostHashTable[index] = chain; + +} + /* * This is called with host locked and held. At this point, the * hostHashTable should not be having entries for the alternate @@ -2088,42 +2117,6 @@ addInterfaceAddr_r(struct host *host, afs_int32 addr) return 0; } -/* inserts a new HashChain structure corresponding to this address */ -void hashInsert_r(afs_int32 addr, struct host* host) -{ - int index; - struct h_hashChain* chain; - - /* hash into proper bucket */ - index = h_HashIndex(addr); - - /* insert into beginning of list for this bucket */ - chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain)); - assert(chain); - chain->hostPtr = host; - chain->next = hostHashTable[index]; - chain->addr = addr; - hostHashTable[index] = chain; - -} - -/* inserts a new HashChain structure corresponding to this UUID */ -void hashInsertUuid_r(struct afsUUID *uuid, struct host* host) -{ - int index; - struct h_hashChain* chain; - - /* hash into proper bucket */ - index = h_UuidHashIndex(uuid); - - /* insert into beginning of list for this bucket */ - chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain)); - assert(chain); - chain->hostPtr = host; - chain->next = hostUuidHashTable[index]; - hostUuidHashTable[index] = chain; -} - /* deleted a HashChain structure for this address and host */ /* returns 1 on success */ int diff --git a/src/viced/host.h b/src/viced/host.h index 8b3655e98..4e8a6ff54 100644 --- a/src/viced/host.h +++ b/src/viced/host.h @@ -147,7 +147,7 @@ extern int rxcon_client_key; an active connection for this to work. If a lwp is working on a request for the client, then the client must have a connection */ /* N.B. h_UserName returns pointer to static data; also relatively expensive */ -extern char *h_UserName(); +extern char *h_UserName(struct client *client); /* all threads whose thread-id is greater than the size of the hold array, ** then use the most significant bit in the 'hold' field in the host structure @@ -167,16 +167,13 @@ extern char *h_UserName(); #define h_holdbit() ( 1<holds[h_holdSlot()] |= h_holdbit()) -extern int h_Hold(); -extern int h_Release(); -extern int h_Release_r(); +extern int h_Release(register struct host *host); +extern int h_Release_r(register struct host *host); #define h_Held_r(host) ((h_holdbit() & (host)->holds[h_holdSlot()]) != 0) -extern int h_Held(); -extern int h_OtherHolds(); -extern int h_OtherHolds_r(); +extern int h_OtherHolds_r(register struct host *host); #define h_Lock(host) ObtainWriteLock(&(host)->lock) -extern int h_Lock_r(); +extern int h_Lock_r(register struct host *host); #define h_Unlock(host) ReleaseWriteLock(&(host)->lock) #define h_Unlock_r(host) ReleaseWriteLock(&(host)->lock) @@ -196,26 +193,21 @@ extern int h_Lock_r(); (h)->prev ? ((h)->prev->next = (h)->next):0;\ ( h == hostList )? (hostList = h->next):0; -extern struct host *h_Alloc(); -extern struct host *h_Alloc_r(); -extern struct host *h_Lookup(); -extern struct host *h_Lookup_r(); -extern struct host *h_LookupUuid_r(); -extern int h_FreeConnection(); -extern int h_Enumerate(); -extern struct host *h_GetHost(); -extern struct host *h_GetHost_r(); -extern struct client *h_FindClient_r(); -extern int h_ReleaseClient_r(); -extern struct client *h_ID2Client(); -extern int GetClient(); -extern h_PrintStats(); -extern h_PrintStats_r(); -extern h_PrintClients(); -extern h_PrintClients_r(); -extern h_GetWorkStats(); -extern h_GetWorkStats_r(); -extern void h_flushhostcps(); +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, int *heldp); +extern struct host *h_LookupUuid_r(afsUUID *uuidp); +extern int h_FreeConnection(struct rx_connection *tcon); +extern void h_Enumerate(int (*proc)(), char *param); +extern struct host *h_GetHost_r(struct rx_connection *tcon); +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 void h_PrintStats(); +extern void h_PrintClients(); +extern void h_GetWorkStats(); +extern void h_flushhostcps(register afs_uint32 hostaddr, register afs_uint32 hport); struct Interface *MultiVerifyInterface_r(); struct host *(hosttableptrs[h_MAXHOSTTABLES]); /* Used by h_itoh */ diff --git a/src/viced/viced.c b/src/viced/viced.c index 667a25865..e66c114a4 100644 --- a/src/viced/viced.c +++ b/src/viced/viced.c @@ -96,11 +96,10 @@ extern int BreakVolumeCallBacks(), InitCallBack(); extern int LogLevel, etext; extern afs_int32 BlocksSpare, PctSpare; -void ShutDown(); +void ShutDown(void); static void ClearXStatValues(), NewParms(), PrintCounters(); static void ResetCheckDescriptors(void), ResetCheckSignal(void); -static int CheckSignal(); -static int FiveMinuteCheckLWP(), HostCheckLWP(); +static void CheckSignal(void); extern int GetKeysFromToken(); extern int RXAFS_ExecuteRequest(); extern int RXSTATS_ExecuteRequest(); @@ -182,15 +181,14 @@ afs_uint32 FS_HostAddrs[ADDRSPERSITE], FS_HostAddr_cnt = 0, FS_registered=0; /* All addresses in FS_HostAddrs are in NBO */ afsUUID FS_HostUUID; -static ParseArgs(); -static FlagMsg(); +static void FlagMsg(); /* * Home for the performance statistics. */ /* DEBUG HACK */ -static CheckDescriptors() +static void CheckDescriptors() { #ifndef AFS_NT40_ENV struct stat status; @@ -210,9 +208,9 @@ static CheckDescriptors() #ifdef AFS_PTHREAD_ENV -void CheckSignal_Signal(x) {CheckSignal(0);} -void ShutDown_Signal(x) {ShutDown(0);} -void CheckDescriptors_Signal(x) {CheckDescriptors(0);} +void CheckSignal_Signal(x) {CheckSignal();} +void ShutDown_Signal(x) {ShutDown();} +void CheckDescriptors_Signal(x) {CheckDescriptors();} #else /* AFS_PTHREAD_ENV */ void CheckSignal_Signal(x) {IOMGR_SoftSig(CheckSignal, 0);} void ShutDown_Signal(x) {IOMGR_SoftSig(ShutDown, 0);} @@ -220,8 +218,7 @@ void CheckDescriptors_Signal(x) {IOMGR_SoftSig(CheckDescriptors, 0);} #endif /* AFS_PTHREAD_ENV */ /* check whether caller is authorized to manage RX statistics */ -int fs_rxstat_userok(call) - struct rx_call *call; +int fs_rxstat_userok(struct rx_call *call) { return afsconf_SuperUser(confDir, call, NULL); } @@ -248,11 +245,7 @@ static void ResetCheckDescriptors(void) /* proc called by rxkad module to get a key */ -static int get_key(arock, akvno, akey) - char *akey; - char *arock; - register afs_int32 akvno; - +static int get_key(char *arock, register afs_int32 akvno, char *akey) { /* find the key */ static struct afsconf_key tkey; @@ -271,9 +264,7 @@ static int get_key(arock, akvno, akey) } /*get_key*/ #ifndef AFS_NT40_ENV -int viced_syscall(a3, a4, a5) -afs_uint32 a3, a4; -void * a5; +int viced_syscall(afs_uint32 a3, afs_uint32 a4, void * a5) { afs_uint32 rcode; void (*old)(); @@ -294,623 +285,266 @@ void * a5; #include "AFS_component_version_number.c" #endif /* !AFS_NT40_ENV */ -main(argc, argv) - int argc; - char * argv[]; +#define MAXADMINNAME 64 +char adminName[MAXADMINNAME]; +static void +CheckAdminName() { - int i; - afs_int32 code; - FILE *file; + int fd = 0; + struct stat status; + + if ((stat("/AdminName", &status)) || /* if file does not exist */ + (status.st_size <= 0) || /* or it is too short */ + (status.st_size >= (MAXADMINNAME)) || /* or it is too long */ + !(fd = open("/AdminName", O_RDONLY, 0))) { /* or the open fails */ + strcpy(adminName, "System:Administrators"); /* use the default name */ + } + else { + read(fd, adminName, status.st_size); /* use name from the file */ + } + if (fd) + close(fd); /* close fd if it was opened */ + +} /*CheckAdminName*/ + + +/* This LWP does things roughly every 5 minutes */ +static void FiveMinuteCheckLWP() +{ + static int msg = 0; char tbuffer[32]; - struct rx_securityClass *sc[4]; - struct rx_service *tservice; + + ViceLog(1, ("Starting five minute check process\n")); + while (1) { #ifdef AFS_PTHREAD_ENV - pthread_t parentPid, serverPid; - pthread_attr_t tattr; - AFS_SIGSET_DECL; + sleep(fiveminutes); #else /* AFS_PTHREAD_ENV */ - PROCESS parentPid, serverPid; + IOMGR_Sleep(fiveminutes); #endif /* AFS_PTHREAD_ENV */ - struct hostent *he; - int minVnodesRequired; /* min size of vnode cache */ -#ifndef AFS_NT40_ENV - struct rlimit rlim; /* max number of open file descriptors */ -#endif - int curLimit; - -#ifdef AFS_AIX32_ENV - struct sigaction nsa; - - sigemptyset(&nsa.sa_mask); - nsa.sa_handler = SIG_DFL; - nsa.sa_flags = SA_FULLDUMP; - sigaction(SIGABRT, &nsa, NULL); - sigaction(SIGSEGV, &nsa, NULL); -#endif - - /* Initialize dirpaths */ - if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) { -#ifdef AFS_NT40_ENV - ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0],0); -#endif - fprintf(stderr,"%s: Unable to obtain AFS server directory.\n", argv[0]); - exit(2); - } + /* close the log so it can be removed */ + ReOpenLog(AFSDIR_SERVER_FILELOG_FILEPATH); /* don't trunc, just append */ + ViceLog(2, ("Cleaning up timed out callbacks\n")); + if(CleanupTimedOutCallBacks()) + ViceLog(5,("Timed out callbacks deleted\n")); + ViceLog(2, ("Set disk usage statistics\n")); + VSetDiskUsage(); + if (FS_registered == 1) Do_VLRegisterRPC(); + if(printBanner && (++msg&1)) { /* Every 10 minutes */ + time_t now = FT_ApproxTime(); + if (console != NULL) { #ifndef AFS_QUIETFS_ENV - console = fopen("/dev/console","w"); -#endif - - if(ParseArgs(argc,argv)) { - FlagMsg(); - exit(-1); + fprintf(console,"File server is running at %s\r", + afs_ctime(&now, tbuffer, sizeof(tbuffer))); +#endif /* AFS_QUIETFS_ENV */ + ViceLog(2, ("File server is running at %s\n", + afs_ctime(&now, tbuffer, sizeof(tbuffer)))); + } + } } +} /*FiveMinuteCheckLWP*/ + +/* This LWP does host checks every 5 minutes: it should not be used for + * other 5 minute activities because it may be delayed by timeouts when + * it probes the workstations + */ +static void HostCheckLWP() +{ + ViceLog(1, ("Starting Host check process\n")); + while(1) { #ifdef AFS_PTHREAD_ENV - assert(pthread_mutex_init(&fileproc_glock_mutex, NULL) == 0); + sleep(fiveminutes); +#else /* AFS_PTHREAD_ENV */ + IOMGR_Sleep(fiveminutes); #endif /* AFS_PTHREAD_ENV */ - -#ifdef AFS_SGI_VNODE_GLUE - if (afs_init_kernel_config(-1) <0) { - printf("Can't determine NUMA configuration, not starting fileserver.\n"); - exit(1); - } -#endif - confDir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH); - if (!confDir) { - fprintf(stderr, "Unable to open config directory %s\n", - AFSDIR_SERVER_ETC_DIRPATH); - exit(-1); + ViceLog(2, ("Checking for dead venii & clients\n")); + h_CheckHosts(); } +} /*HostCheckLWP*/ - NewParms(1); - /* Open FileLog on stdout, stderr, fd 1 and fd2 (for perror), sigh. */ - OpenLog(AFSDIR_SERVER_FILELOG_FILEPATH); - SetupLogSignals(); +/*------------------------------------------------------------------------ + * PRIVATE ClearXStatValues + * + * Description: + * Initialize all of the values collected via the xstat + * interface. + * + * Arguments: + * None. + * + * Returns: + * Nothing. + * + * Environment: + * Must be called during File Server initialization. + * + * Side Effects: + * As advertised. + *------------------------------------------------------------------------*/ - if (SawSpare && SawPctSpare) { - ViceLog(0, ("Both -spare and -pctspare specified, exiting.\n")); - exit(-1); - } +static void ClearXStatValues() +{ /*ClearXStatValues*/ -#ifdef AFS_SGI_XFS_IOPS_ENV - ViceLog(0, ("XFS/EFS File server starting\n")); -#else - ViceLog(0, ("File server starting\n")); -#endif + struct fs_stats_opTimingData *opTimeP; /*Ptr to timing struct*/ + struct fs_stats_xferData *opXferP; /*Ptr to xfer struct*/ + int i; /*Loop counter*/ - /* install signal handlers for controlling the fileserver process */ - ResetCheckSignal(); /* set CheckSignal_Signal() sig handler */ - ResetCheckDescriptors(); /* set CheckDescriptors_Signal() sig handler */ + /* + * Zero all xstat-related structures. + */ + memset((char *)(&afs_perfstats), 0, sizeof(struct afs_PerfStats)); +#if FS_STATS_DETAILED + memset((char *)(&afs_FullPerfStats), 0, sizeof(struct fs_stats_FullPerfStats)); -#if defined(AFS_SGI_ENV) - /* give this guy a non-degrading priority so help busy servers */ - schedctl(NDPRI, 0, NDPNORMMAX); - if (SawLock) - plock(PROCLOCK); + /* + * That's not enough. We have to set reasonable minima for + * time and xfer values in the detailed stats. + */ + opTimeP = &(afs_FullPerfStats.det.rpcOpTimes[0]); + for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++, opTimeP++) + opTimeP->minTime.tv_sec = 999999; + + opXferP = &(afs_FullPerfStats.det.xferOpTimes[0]); + for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++, opXferP++) { + opXferP->minTime.tv_sec = 999999; + opXferP->minBytes = 999999999; + } + + /* + * There's more. We have to set our unique system identifier, as + * declared in param.h. If such a thing is not defined, we bitch + * and declare ourselves to be an unknown system type. + */ +#ifdef SYS_NAME_ID + afs_perfstats.sysname_ID = SYS_NAME_ID; #else #ifndef AFS_NT40_ENV - nice(-5); /* TODO: */ -#endif + ViceLog(0, ("Sys name ID constant not defined in param.h!!\n")); + ViceLog(0, ("[Choosing ``undefined'' sys name ID.\n")); #endif - assert(DInit(buffs) == 0); - -#ifdef AFS_NT40_ENV - if (afs_winsockInit()<0) { - ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0); - ViceLog(0, ("File server failed to intialize winsock.\n")); - exit(1); - } + afs_perfstats.sysname_ID = SYS_NAME_ID_UNDEFINED; +#endif /* SYS_NAME_ID */ #endif - CheckAdminName(); - - /* if we support more than 16 threads, then we better have the ability - ** to keep open a large number of files simultaneously - */ -#if defined(AFS_AIX_ENV) && !defined(AFS_AIX42_ENV) - curLimit = OPEN_MAX; /* for pre AIX 4.2 systems */ -#elif defined(AFS_NT40_ENV) - curLimit = NT_OPEN_MAX; /* open file descriptor limit on NT */ -#else - - curLimit = 0; /* the number of open file descriptors */ - code = getrlimit(RLIMIT_NOFILE, &rlim); - if (code == 0) { - curLimit = rlim.rlim_cur; - rlim.rlim_cur = rlim.rlim_max; - code = setrlimit(RLIMIT_NOFILE, &rlim); - if ( code == 0 ) - curLimit = rlim.rlim_max; - } - if ( code != 0 ) - ViceLog(0, ("Failed to increase open file limit, using default\n")); - -#endif /* defined(AFS_AIX_ENV) && !defined(AFS_AIX42_ENV) */ - - curLimit -= 32; /* leave a slack of 32 file descriptors */ - if ( lwps > curLimit ) { - if ( curLimit > 0) - lwps = curLimit; - else if ( lwps > 16 ) - lwps = 16; /* default to a maximum of 16 threads */ - ViceLog(0, ("The system supports a max of %d open files and we are starting %d threads\n", curLimit, lwps)); - } +} /*ClearXStatValues*/ -#ifndef AFS_PTHREAD_ENV - assert(LWP_InitializeProcessSupport(LWP_MAX_PRIORITY - 2, &parentPid) == LWP_SUCCESS); -#endif /* !AFS_PTHREAD_ENV */ - /* Initialize volume support */ - if (!novbc) { - V_BreakVolumeCallbacks = BreakVolumeCallBacks; - } +static void PrintCounters() +{ + int dirbuff, dircall, dirio; + struct timeval tpl; + int workstations, activeworkstations, delworkstations; + int processSize = 0; + char tbuffer[32]; - /* initialize libacl routines */ - acl_Initialize(ACL_VERSION); + TM_GetTimeOfDay(&tpl, 0); + Statistics = 1; + ViceLog(0, ("Vice was last started at %s\n", + afs_ctime(&StartTime, tbuffer, sizeof(tbuffer)))); - /* initialize RX support */ -#ifndef AFS_NT40_ENV - rxi_syscallp = viced_syscall; -#endif - rx_extraPackets = rxpackets; - rx_extraQuota = 4; /* for outgoing prserver calls from R threads */ - rx_SetBusyThreshold(busy_threshold, VBUSY); - rx_SetCallAbortThreshold(10); - rx_SetConnAbortThreshold(10); - stackSize = lwps * 4000; - if (stackSize < 32000) - stackSize = 32000; - else if (stackSize > 44000) - stackSize = 44000; -#if defined(AFS_HPUX_ENV) || defined(AFS_SUN_ENV) || defined(AFS_SGI51_ENV) - rx_SetStackSize(1, stackSize); + VPrintCacheStats(); + VPrintDiskStats(); + DStat(&dirbuff, &dircall, &dirio); + ViceLog(0,("With %d directory buffers; %d reads resulted in %d read I/Os\n", + dirbuff, dircall, dirio)); + rx_PrintStats(stderr); + h_PrintStats(); + PrintCallBackStats(); +#ifdef AFS_NT40_ENV + processSize = -1; /* TODO: */ +#else + processSize = (int)((long) sbrk(0) >> 10); #endif - if ( udpBufSize ) - rx_SetUdpBufSize(udpBufSize);/* set the UDP buffer size for receive */ - if (rx_Init((int)htons(7000))<0) { - ViceLog(0, ("Cannot initialize RX\n")); - exit(1); - } - if (!rxJumbograms) { - /* Don't send and don't allow 3.4 clients to send jumbograms. */ - rx_SetNoJumbo(); - } - rx_GetIFInfo(); - rx_SetRxDeadTime(30); - sc[0] = rxnull_NewServerSecurityObject(); - sc[1] = 0; /* rxvab_NewServerSecurityObject(key1, 0) */ - sc[2] = rxkad_NewServerSecurityObject (rxkad_clear, NULL, - get_key, NULL); - sc[3] = rxkad_NewServerSecurityObject (rxkad_crypt, NULL, - get_key, NULL); - tservice = rx_NewService - (/* port */ 0, /* service id */ 1, /*service name */ "AFS", - /* security classes */ sc, /* numb sec classes */ 4, - RXAFS_ExecuteRequest); - if (!tservice) { - ViceLog(0, ("Failed to initialize RX, probably two servers running.\n")); - exit(-1); - } - rx_SetDestroyConnProc(tservice, h_FreeConnection); - rx_SetMinProcs(tservice, 3); - rx_SetMaxProcs(tservice, lwps); - rx_SetCheckReach(tservice, 1); - - tservice = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", sc, 4, RXSTATS_ExecuteRequest); - if (!tservice) { - ViceLog(0, ("Failed to initialize rpc stat service.\n")); - exit(-1); - } - rx_SetMinProcs(tservice, 2); - rx_SetMaxProcs(tservice, 4); - - /* - * Enable RX hot threads, which allows the listener thread to trade - * places with an idle thread and moves the context switch from listener - * to worker out of the critical path. - */ - rx_EnableHotThread(); - - /* Some rx debugging */ - if (rxlog || eventlog) { - debugFile = fopen("rx_dbg", "w"); - if (rxlog) rx_debugFile = debugFile; - if (eventlog) rxevent_debugFile = debugFile; - } - - h_InitHostPackage(); /* set up local cellname and realmname */ - InitCallBack(numberofcbs); - ClearXStatValues(); - - code = InitVL(); - if (code) { - ViceLog(0,("Fatal error in library initialization, exiting!!\n")); - exit(1); - } - - code = InitPR(); - if (code) { - ViceLog(0,("Fatal error in protection initialization, exiting!!\n")); - exit(1); - } + ViceLog(0,("There are %d connections, process size %d\n", CurrentConnections, processSize)); + h_GetWorkStats(&workstations, &activeworkstations, &delworkstations, + tpl.tv_sec-15*60); + ViceLog(0, + ("There are %d workstations, %d are active (req in < 15 mins), %d marked \"down\"\n", + workstations, activeworkstations, delworkstations)); + Statistics = 0; - /* allow super users to manage RX statistics */ - rx_SetRxStatUserOk(fs_rxstat_userok); +} /*PrintCounters*/ - rx_StartServer(0); /* now start handling requests */ - /* we ensure that there is enough space in the vnode buffer to satisfy - ** requests from all concurrent threads. - ** the maximum number of vnodes used by a single thread at any one time - ** is three ( "link" uses three vnodes simultaneously, one vLarge and - ** two vSmall for linking files and two vLarge and one vSmall for linking - ** files ) : dhruba - */ - minVnodesRequired = 2 * lwps + 1; - if ( minVnodesRequired > nSmallVns ) { - nSmallVns = minVnodesRequired; - ViceLog(0, ("Overriding -s command line parameter with %d\n", - nSmallVns)); - } - if ( minVnodesRequired > large ) { - large = minVnodesRequired; - ViceLog(0, ("Overriding -l command line parameter with %d\n", large)); - } - /* We now do this after getting the listener up and running, so that client - connections don't timeout (maybe) if a file server is restarted, since it - will be available "real soon now". Worry about whether we can satisfy the - calls in the volume package itself. - */ - if (VInitVolumePackage(fileServer,large,nSmallVns,0, volcache)) { - ViceLog(0, ("Shutting down: errors encountered initializing volume package\n")); - VShutdown(); - exit(1); +static void CheckSignal() +{ + if (FS_registered > 0) { + /* + * We have proper ip addresses; tell the vlserver what we got; the following + * routine will do the proper reporting for us + */ + Do_VLRegisterRPC(); } + h_DumpHosts(); + h_PrintClients(); + DumpCallBackState(); + PrintCounters(); + ResetCheckSignal(); - /* - * We are done calling fopen/fdopen. It is safe to use a large - * of the file descriptor cache. - */ - ih_UseLargeCache(); - -#ifdef AFS_PTHREAD_ENV - assert(pthread_attr_init(&tattr) == 0); - assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0); - /* Block signals in the threads */ - AFS_SIGSET_CLEAR(); - assert(pthread_create(&serverPid, &tattr, (void *)FiveMinuteCheckLWP, &fiveminutes) == 0); - assert(pthread_create(&serverPid, &tattr, (void *)HostCheckLWP, &fiveminutes) == 0); - AFS_SIGSET_RESTORE(); -#else /* AFS_PTHREAD_ENV */ - assert(LWP_CreateProcess(FiveMinuteCheckLWP, stack*1024, LWP_MAX_PRIORITY - 2, - (void *) &fiveminutes, "FiveMinuteChecks", &serverPid) == LWP_SUCCESS); - - assert(LWP_CreateProcess(HostCheckLWP, stack*1024, LWP_MAX_PRIORITY - 2, - (void *) &fiveminutes, "HostCheck", &serverPid) == LWP_SUCCESS); -#endif /* AFS_PTHREAD_ENV */ +} /*CheckSignal*/ - TM_GetTimeOfDay(&tp, 0); +void ShutDownAndCore(int dopanic) +{ + time_t now = time(0); + char *tstr; + char tbuffer[32]; + ViceLog(0, ("Shutting down file server at %s", + afs_ctime(&now, tbuffer, sizeof(tbuffer)))); + if (dopanic) + ViceLog(0, ("ABNORMAL SHUTDOWN, see core file.\n")); #ifndef AFS_QUIETFS_ENV if (console != NULL) { - fprintf(console, "File server has started at %s\r", - afs_ctime(&tp.tv_sec, tbuffer, sizeof(tbuffer))); + fprintf(console,"File server restart/shutdown received at %s\r", + afs_ctime(&now, tbuffer, sizeof(tbuffer))); } #endif + DFlush(); + PrintCounters(); - /* - * Figure out the FileServer's name and primary address. - */ - ViceLog(0, ("Getting FileServer name...\n")); - code = gethostname(FS_HostName, 64); - if (code) { - ViceLog(0, ("gethostname() failed\n")); - } - ViceLog(0, ("FileServer host name is '%s'\n", FS_HostName)); + /* do not allows new reqests to be served from now on, all new requests + are returned with an error code of RX_RESTARTING ( transient failure ) */ + rx_SetRxTranquil(); /* dhruba */ + VShutdown(); - ViceLog(0, ("Getting FileServer address...\n")); - he = gethostbyname(FS_HostName); - if (!he) { - ViceLog(0, ("Can't find address for FileServer '%s'\n", FS_HostName)); - } - else { - char hoststr[16]; - memcpy(&FS_HostAddr_NBO, he->h_addr, 4); - afs_inet_ntoa_r(FS_HostAddr_NBO, hoststr); - FS_HostAddr_HBO = ntohl(FS_HostAddr_NBO); - ViceLog(0,("FileServer %s has address %s (0x%x or 0x%x in host byte order)\n", - FS_HostName, hoststr, FS_HostAddr_NBO, FS_HostAddr_HBO)); + if (debugFile) { + rx_PrintStats(debugFile); + fflush(debugFile); } - - /* Install handler to catch the shutdown signal */ - signal(SIGQUIT, ShutDown_Signal); /* bosserver assumes SIGQUIT shutdown */ - - ViceLog(0,("File Server started %s", - afs_ctime(&tp.tv_sec, tbuffer, sizeof(tbuffer)))); -#if FS_STATS_DETAILED - afs_FullPerfStats.det.epoch.tv_sec = StartTime = tp.tv_sec; + if (console != NULL) { + now = time(0); + if (dopanic) { +#ifndef AFS_QUIETFS_ENV + fprintf(console, "File server has terminated abnormally at %s\r", + afs_ctime(&now, tbuffer, sizeof(tbuffer))); #endif -#ifdef AFS_PTHREAD_ENV - while(1) { - sleep(1000); /* long time */ + ViceLog(0, ("File server has terminated abnormally at %s\n", + afs_ctime(&now, tbuffer, sizeof(tbuffer)))); + } else { +#ifndef AFS_QUIETFS_ENV + fprintf(console, "File server has terminated normally at %s\r", + afs_ctime(&now, tbuffer, sizeof(tbuffer))); +#endif + ViceLog(0, ("File server has terminated normally at %s\n", + afs_ctime(&now, tbuffer, sizeof(tbuffer)))); + } } -#else /* AFS_PTHREAD_ENV */ - assert(LWP_WaitProcess(&parentPid) == LWP_SUCCESS); -#endif /* AFS_PTHREAD_ENV */ -} + exit(0); -/* This LWP does things roughly every 5 minutes */ -static FiveMinuteCheckLWP() +} /*ShutDown*/ +void ShutDown(void) /* backward compatibility */ { - static int msg = 0; - char tbuffer[32]; + ShutDownAndCore(DONTPANIC); +} - ViceLog(1, ("Starting five minute check process\n")); - while (1) { -#ifdef AFS_PTHREAD_ENV - sleep(fiveminutes); -#else /* AFS_PTHREAD_ENV */ - IOMGR_Sleep(fiveminutes); -#endif /* AFS_PTHREAD_ENV */ - - /* close the log so it can be removed */ - ReOpenLog(AFSDIR_SERVER_FILELOG_FILEPATH); /* don't trunc, just append */ - ViceLog(2, ("Cleaning up timed out callbacks\n")); - if(CleanupTimedOutCallBacks()) - ViceLog(5,("Timed out callbacks deleted\n")); - ViceLog(2, ("Set disk usage statistics\n")); - VSetDiskUsage(); - if (FS_registered == 1) Do_VLRegisterRPC(); - if(printBanner && (++msg&1)) { /* Every 10 minutes */ - time_t now = FT_ApproxTime(); - if (console != NULL) { -#ifndef AFS_QUIETFS_ENV - fprintf(console,"File server is running at %s\r", - afs_ctime(&now, tbuffer, sizeof(tbuffer))); -#endif /* AFS_QUIETFS_ENV */ - ViceLog(2, ("File server is running at %s\n", - afs_ctime(&now, tbuffer, sizeof(tbuffer)))); - } - } - } -} /*FiveMinuteCheckLWP*/ - - -/* This LWP does host checks every 5 minutes: it should not be used for - * other 5 minute activities because it may be delayed by timeouts when - * it probes the workstations - */ -static HostCheckLWP() - -{ - ViceLog(1, ("Starting Host check process\n")); - while(1) { -#ifdef AFS_PTHREAD_ENV - sleep(fiveminutes); -#else /* AFS_PTHREAD_ENV */ - IOMGR_Sleep(fiveminutes); -#endif /* AFS_PTHREAD_ENV */ - ViceLog(2, ("Checking for dead venii & clients\n")); - h_CheckHosts(); - } -} /*HostCheckLWP*/ - - -#define MAXADMINNAME 64 -char adminName[MAXADMINNAME]; - -CheckAdminName() - -{ - int fd = 0; - struct stat status; - - if ((stat("/AdminName", &status)) || /* if file does not exist */ - (status.st_size <= 0) || /* or it is too short */ - (status.st_size >= (MAXADMINNAME)) || /* or it is too long */ - !(fd = open("/AdminName", O_RDONLY, 0))) { /* or the open fails */ - strcpy(adminName, "System:Administrators"); /* use the default name */ - } - else { - read(fd, adminName, status.st_size); /* use name from the file */ - } - if (fd) - close(fd); /* close fd if it was opened */ - -} /*CheckAdminName*/ - - -/*------------------------------------------------------------------------ - * PRIVATE ClearXStatValues - * - * Description: - * Initialize all of the values collected via the xstat - * interface. - * - * Arguments: - * None. - * - * Returns: - * Nothing. - * - * Environment: - * Must be called during File Server initialization. - * - * Side Effects: - * As advertised. - *------------------------------------------------------------------------*/ - -static void ClearXStatValues() - -{ /*ClearXStatValues*/ - - struct fs_stats_opTimingData *opTimeP; /*Ptr to timing struct*/ - struct fs_stats_xferData *opXferP; /*Ptr to xfer struct*/ - int i; /*Loop counter*/ - - /* - * Zero all xstat-related structures. - */ - memset((char *)(&afs_perfstats), 0, sizeof(struct afs_PerfStats)); -#if FS_STATS_DETAILED - memset((char *)(&afs_FullPerfStats), 0, sizeof(struct fs_stats_FullPerfStats)); - - /* - * That's not enough. We have to set reasonable minima for - * time and xfer values in the detailed stats. - */ - opTimeP = &(afs_FullPerfStats.det.rpcOpTimes[0]); - for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++, opTimeP++) - opTimeP->minTime.tv_sec = 999999; - - opXferP = &(afs_FullPerfStats.det.xferOpTimes[0]); - for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++, opXferP++) { - opXferP->minTime.tv_sec = 999999; - opXferP->minBytes = 999999999; - } - - /* - * There's more. We have to set our unique system identifier, as - * declared in param.h. If such a thing is not defined, we bitch - * and declare ourselves to be an unknown system type. - */ -#ifdef SYS_NAME_ID - afs_perfstats.sysname_ID = SYS_NAME_ID; -#else -#ifndef AFS_NT40_ENV - ViceLog(0, ("Sys name ID constant not defined in param.h!!\n")); - ViceLog(0, ("[Choosing ``undefined'' sys name ID.\n")); -#endif - afs_perfstats.sysname_ID = SYS_NAME_ID_UNDEFINED; -#endif /* SYS_NAME_ID */ -#endif - -} /*ClearXStatValues*/ - - -static void PrintCounters() - -{ - int dirbuff, dircall, dirio; - struct timeval tpl; - int workstations, activeworkstations, delworkstations; - int processSize = 0; - char tbuffer[32]; - - TM_GetTimeOfDay(&tpl, 0); - Statistics = 1; - ViceLog(0, ("Vice was last started at %s\n", - afs_ctime(&StartTime, tbuffer, sizeof(tbuffer)))); - - VPrintCacheStats(); - VPrintDiskStats(); - DStat(&dirbuff, &dircall, &dirio); - ViceLog(0,("With %d directory buffers; %d reads resulted in %d read I/Os\n", - dirbuff, dircall, dirio)); - rx_PrintStats(stderr); - h_PrintStats(); - PrintCallBackStats(); -#ifdef AFS_NT40_ENV - processSize = -1; /* TODO: */ -#else - processSize = (int)((long) sbrk(0) >> 10); -#endif - ViceLog(0,("There are %d connections, process size %d\n", CurrentConnections, processSize)); - h_GetWorkStats(&workstations, &activeworkstations, &delworkstations, - tpl.tv_sec-15*60); - ViceLog(0, - ("There are %d workstations, %d are active (req in < 15 mins), %d marked \"down\"\n", - workstations, activeworkstations, delworkstations)); - Statistics = 0; - -} /*PrintCounters*/ - - - -static CheckSignal() - -{ - if (FS_registered > 0) { - /* - * We have proper ip addresses; tell the vlserver what we got; the following - * routine will do the proper reporting for us - */ - Do_VLRegisterRPC(); - } - h_DumpHosts(); - h_PrintClients(); - DumpCallBackState(); - PrintCounters(); - ResetCheckSignal(); - -} /*CheckSignal*/ - -void ShutDownAndCore(dopanic) -int dopanic; -{ - time_t now = time(0); - char *tstr; - char tbuffer[32]; - - ViceLog(0, ("Shutting down file server at %s", - afs_ctime(&now, tbuffer, sizeof(tbuffer)))); - if (dopanic) - ViceLog(0, ("ABNORMAL SHUTDOWN, see core file.\n")); -#ifndef AFS_QUIETFS_ENV - if (console != NULL) { - fprintf(console,"File server restart/shutdown received at %s\r", - afs_ctime(&now, tbuffer, sizeof(tbuffer))); - } -#endif - DFlush(); - PrintCounters(); - - /* do not allows new reqests to be served from now on, all new requests - are returned with an error code of RX_RESTARTING ( transient failure ) */ - rx_SetRxTranquil(); /* dhruba */ - VShutdown(); - - if (debugFile) { - rx_PrintStats(debugFile); - fflush(debugFile); - } - if (console != NULL) { - now = time(0); - if (dopanic) { -#ifndef AFS_QUIETFS_ENV - fprintf(console, "File server has terminated abnormally at %s\r", - afs_ctime(&now, tbuffer, sizeof(tbuffer))); -#endif - ViceLog(0, ("File server has terminated abnormally at %s\n", - afs_ctime(&now, tbuffer, sizeof(tbuffer)))); - } else { -#ifndef AFS_QUIETFS_ENV - fprintf(console, "File server has terminated normally at %s\r", - afs_ctime(&now, tbuffer, sizeof(tbuffer))); -#endif - ViceLog(0, ("File server has terminated normally at %s\n", - afs_ctime(&now, tbuffer, sizeof(tbuffer)))); - } - } - - exit(0); - -} /*ShutDown*/ - -void ShutDown() /* backward compatibility */ -{ - ShutDownAndCore(DONTPANIC); -} - - -static FlagMsg() +static void FlagMsg() { char buffer[1024]; @@ -960,8 +594,7 @@ static FlagMsg() } /*FlagMsg*/ -static afs_int32 ParseRights(arights) - char *arights; +static afs_int32 ParseRights(char *arights) { afs_int32 mode = 0; int i, len; @@ -1036,10 +669,7 @@ max_fileserver_thread(void) return MAX_FILESERVER_THREAD; } -static ParseArgs(argc, argv) - int argc; - char *argv[]; - +static int ParseArgs(int argc, char *argv[]) { int SawL=0, SawS=0, SawVC=0; int Sawrxpck = 0, Sawsmall=0, Sawlarge=0, Sawcbs=0, Sawlwps=0, Sawbufs=0; @@ -1150,8 +780,8 @@ static ParseArgs(argc, argv) if (!strcmp(argv[i], "-cb")) { Sawcbs = 1; numberofcbs = atoi(argv[++i]); - if ((numberofcbs < 10000) || (numberofcbs > 4294967295)) { - printf("number of cbs %d invalid; must be between 10000 and 4294967295\n", + if ((numberofcbs < 10000) || (numberofcbs > 2147483647)) { + printf("number of cbs %d invalid; must be between 10000 and 2147483647\n", numberofcbs); return -1; } @@ -1259,9 +889,7 @@ static ParseArgs(argc, argv) #define MAXPARMS 15 -static void NewParms(initializing) - int initializing; - +static void NewParms(int initializing) { static struct stat sbuf; register int i, fd; @@ -1326,9 +954,7 @@ static void NewParms(initializing) /* Miscellaneous routines */ -Die (msg) - char *msg; - +void Die (char *msg) { ViceLog (0,("%s\n", msg)); assert(0); @@ -1336,8 +962,7 @@ Die (msg) } /*Die*/ -InitPR() - +afs_int32 InitPR() { register code; @@ -1382,8 +1007,8 @@ sleep: struct rx_connection *serverconns[MAXSERVERS]; struct ubik_client *cstruct; -afs_int32 vl_Initialize(confDir) -char *confDir; + +afs_int32 vl_Initialize(char *confDir) { afs_int32 code, scIndex = 0, i; struct afsconf_dir *tdir; struct rx_securityClass *sc; @@ -1418,6 +1043,7 @@ char *confDir; #define SYSIDMAGIC 0x88aabbcc #define SYSIDVERSION 1 +afs_int32 ReadSysIdFile() { afs_int32 fd, nentries, i; struct versionStamp vsn; @@ -1470,6 +1096,7 @@ ReadSysIdFile() { return 0; } +afs_int32 WriteSysIdFile() { afs_int32 fd, nentries, i; struct versionStamp vsn; @@ -1493,139 +1120,489 @@ WriteSysIdFile() { ViceLog(0, ("%s: write failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno)); return EIO; } - uuid = FS_HostUUID; - afs_htonuuid(&uuid); - if ((i = write(fd, (char *)&uuid, sizeof(struct afsUUID))) != sizeof(struct afsUUID)) { - ViceLog(0, ("%s: write of uuid failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno)); - return EIO; + uuid = FS_HostUUID; + afs_htonuuid(&uuid); + if ((i = write(fd, (char *)&uuid, sizeof(struct afsUUID))) != sizeof(struct afsUUID)) { + ViceLog(0, ("%s: write of uuid failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno)); + return EIO; + } + if ((i = write(fd, (char *)&FS_HostAddr_cnt, sizeof(afs_int32))) != sizeof(afs_int32)) { + ViceLog(0, ("%s: write of # of entries failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno)); + return EIO; + } + for (i = 0; i < FS_HostAddr_cnt; i++) { + if (write(fd, (char *)&FS_HostAddrs[i], sizeof(afs_int32)) != sizeof(afs_int32)) { + ViceLog(0, ("%s: write of addresses failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno)); + return EIO; + } + } + close(fd); + return 0; +} + +/* + * defect 10966 + * This routine sets up the buffers for the VL_RegisterAddrs RPC. All addresses + * in FS_HostAddrs[] are in NBO, while the RPC treats them as a "blob" of data + * and so we need to convert each of them into HBO which is what the extra + * array called FS_HostAddrs_HBO is used here. + */ +afs_int32 +Do_VLRegisterRPC() { + register int code; + bulkaddrs addrs; + extern int VL_RegisterAddrs(); + afs_uint32 FS_HostAddrs_HBO[ADDRSPERSITE]; + int i=0; + + for (i=0; i < FS_HostAddr_cnt ; i++) + FS_HostAddrs_HBO[i]=ntohl(FS_HostAddrs[i]); + addrs.bulkaddrs_len = FS_HostAddr_cnt; + addrs.bulkaddrs_val = (afs_uint32 *)FS_HostAddrs_HBO; + code = ubik_Call(VL_RegisterAddrs, cstruct, 0, &FS_HostUUID, 0, &addrs); + if (code) { + if (code == VL_MULTIPADDR) { + ViceLog(0, ("VL_RegisterAddrs rpc failed; The ethernet address exist on a different server; repair it\n")); + ViceLog(0, ("VL_RegisterAddrs rpc failed; See VLLog for details\n")); + return code; + } else if (code == RXGEN_OPCODE) { + ViceLog(0, ("vlserver doesn't support VL_RegisterAddrs rpc; ignored\n")); + FS_registered = 2; /* So we don't have to retry in the gc daemon */ + } else { + ViceLog(0, ("VL_RegisterAddrs rpc failed; will retry periodically (code=%d, err=%d)\n", + code, errno)); + } + } else { + FS_registered = 2; /* So we don't have to retry in the gc daemon */ + WriteSysIdFile(); + } + + return 0; +} + +#if 0 +static int AddrsEqual(cnt, addr1, addr2) + int cnt; + afs_int32 *addr1, *addr2; +{ + register int i, j; + + for (i = 0; i < cnt; i++) { + for (j = 0; j < cnt; j++) { + if (addr1[i] == addr2[j]) break; + } + if (j == cnt) return 0; + } + return 1; +} +#endif + +afs_int32 +InitVL() { + int (*old)(); + afs_int32 code; + afs_int32 cnt, i; + extern int rxi_numNetAddrs; + extern afs_uint32 rxi_NetAddrs[]; + + /* + * If this fails, it's because something major is wrong, and is not + * likely to be time dependent. + */ + code = vl_Initialize(AFSDIR_SERVER_ETC_DIRPATH); + if (code != 0) { + ViceLog(0, ("Couldn't initialize protection library; code=%d.\n", code)); + return code; + } + + /* Read or create the sysid file and register the fileserver's + * IP addresses with the vlserver. + */ + code = ReadSysIdFile(); + if (code) { + /* Need to create the file */ + ViceLog(0, ("Creating new SysID file\n")); + if ((code = afs_uuid_create(&FS_HostUUID))) { + ViceLog(0, ("Failed to create new uuid: %d\n", code)); + exit(1); + } + } + /* A good sysid file exists; inform the vlserver. If any conflicts, + * we always use the latest interface available as the real truth. + */ +#ifndef AFS_NT40_ENV + if(AFSDIR_SERVER_NETRESTRICT_FILEPATH || AFSDIR_SERVER_NETINFO_FILEPATH) { + /* + * Find addresses we are supposed to register as per the netrestrict + * and netinfo files (/usr/afs/local/NetInfo and + * /usr/afs/local/NetRestict) + */ + char reason[1024]; + afs_int32 code = parseNetFiles(FS_HostAddrs,NULL, NULL, + ADDRSPERSITE, reason, + AFSDIR_SERVER_NETINFO_FILEPATH, + AFSDIR_SERVER_NETRESTRICT_FILEPATH); + if (code < 0) { + ViceLog(0,("Can't register any valid addresses: %s\n",reason)); + exit(1); + } + FS_HostAddr_cnt = (afs_uint32) code; + } + else +#endif + { + FS_HostAddr_cnt = rx_getAllAddr(FS_HostAddrs, ADDRSPERSITE); + } + + FS_registered = 1; + code = Do_VLRegisterRPC(); + return code; +} + +int +main(int argc, char * argv[]) +{ + int i; + afs_int32 code; + FILE *file; + char tbuffer[32]; + struct rx_securityClass *sc[4]; + struct rx_service *tservice; +#ifdef AFS_PTHREAD_ENV + pthread_t parentPid, serverPid; + pthread_attr_t tattr; + AFS_SIGSET_DECL; +#else /* AFS_PTHREAD_ENV */ + PROCESS parentPid, serverPid; +#endif /* AFS_PTHREAD_ENV */ + struct hostent *he; + int minVnodesRequired; /* min size of vnode cache */ +#ifndef AFS_NT40_ENV + struct rlimit rlim; /* max number of open file descriptors */ +#endif + int curLimit; + +#ifdef AFS_AIX32_ENV + struct sigaction nsa; + + sigemptyset(&nsa.sa_mask); + nsa.sa_handler = SIG_DFL; + nsa.sa_flags = SA_FULLDUMP; + sigaction(SIGABRT, &nsa, NULL); + sigaction(SIGSEGV, &nsa, NULL); +#endif + + /* Initialize dirpaths */ + if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) { +#ifdef AFS_NT40_ENV + ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0],0); +#endif + fprintf(stderr,"%s: Unable to obtain AFS server directory.\n", argv[0]); + exit(2); + } + +#ifndef AFS_QUIETFS_ENV + console = fopen("/dev/console","w"); +#endif + + if(ParseArgs(argc,argv)) { + FlagMsg(); + exit(-1); + } + +#ifdef AFS_PTHREAD_ENV + assert(pthread_mutex_init(&fileproc_glock_mutex, NULL) == 0); +#endif /* AFS_PTHREAD_ENV */ + +#ifdef AFS_SGI_VNODE_GLUE + if (afs_init_kernel_config(-1) <0) { + printf("Can't determine NUMA configuration, not starting fileserver.\n"); + exit(1); + } +#endif + confDir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH); + if (!confDir) { + fprintf(stderr, "Unable to open config directory %s\n", + AFSDIR_SERVER_ETC_DIRPATH); + exit(-1); + } + + NewParms(1); + + /* Open FileLog on stdout, stderr, fd 1 and fd2 (for perror), sigh. */ + OpenLog(AFSDIR_SERVER_FILELOG_FILEPATH); + SetupLogSignals(); + + if (SawSpare && SawPctSpare) { + ViceLog(0, ("Both -spare and -pctspare specified, exiting.\n")); + exit(-1); + } + +#ifdef AFS_SGI_XFS_IOPS_ENV + ViceLog(0, ("XFS/EFS File server starting\n")); +#else + ViceLog(0, ("File server starting\n")); +#endif + + /* install signal handlers for controlling the fileserver process */ + ResetCheckSignal(); /* set CheckSignal_Signal() sig handler */ + ResetCheckDescriptors(); /* set CheckDescriptors_Signal() sig handler */ + +#if defined(AFS_SGI_ENV) + /* give this guy a non-degrading priority so help busy servers */ + schedctl(NDPRI, 0, NDPNORMMAX); + if (SawLock) + plock(PROCLOCK); +#else +#ifndef AFS_NT40_ENV + nice(-5); /* TODO: */ +#endif +#endif + assert(DInit(buffs) == 0); + +#ifdef AFS_NT40_ENV + if (afs_winsockInit()<0) { + ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0); + ViceLog(0, ("File server failed to intialize winsock.\n")); + exit(1); + } +#endif + CheckAdminName(); + + /* if we support more than 16 threads, then we better have the ability + ** to keep open a large number of files simultaneously + */ +#if defined(AFS_AIX_ENV) && !defined(AFS_AIX42_ENV) + curLimit = OPEN_MAX; /* for pre AIX 4.2 systems */ +#elif defined(AFS_NT40_ENV) + curLimit = NT_OPEN_MAX; /* open file descriptor limit on NT */ +#else + + curLimit = 0; /* the number of open file descriptors */ + code = getrlimit(RLIMIT_NOFILE, &rlim); + if (code == 0) { + curLimit = rlim.rlim_cur; + rlim.rlim_cur = rlim.rlim_max; + code = setrlimit(RLIMIT_NOFILE, &rlim); + if ( code == 0 ) + curLimit = rlim.rlim_max; + } + if ( code != 0 ) + ViceLog(0, ("Failed to increase open file limit, using default\n")); + +#endif /* defined(AFS_AIX_ENV) && !defined(AFS_AIX42_ENV) */ + + curLimit -= 32; /* leave a slack of 32 file descriptors */ + if ( lwps > curLimit ) { + if ( curLimit > 0) + lwps = curLimit; + else if ( lwps > 16 ) + lwps = 16; /* default to a maximum of 16 threads */ + ViceLog(0, ("The system supports a max of %d open files and we are starting %d threads\n", curLimit, lwps)); + } + + +#ifndef AFS_PTHREAD_ENV + assert(LWP_InitializeProcessSupport(LWP_MAX_PRIORITY - 2, &parentPid) == LWP_SUCCESS); +#endif /* !AFS_PTHREAD_ENV */ + + /* Initialize volume support */ + if (!novbc) { + V_BreakVolumeCallbacks = BreakVolumeCallBacks; + } + + /* initialize libacl routines */ + acl_Initialize(ACL_VERSION); + + /* initialize RX support */ +#ifndef AFS_NT40_ENV + rxi_syscallp = viced_syscall; +#endif + rx_extraPackets = rxpackets; + rx_extraQuota = 4; /* for outgoing prserver calls from R threads */ + rx_SetBusyThreshold(busy_threshold, VBUSY); + rx_SetCallAbortThreshold(10); + rx_SetConnAbortThreshold(10); + stackSize = lwps * 4000; + if (stackSize < 32000) + stackSize = 32000; + else if (stackSize > 44000) + stackSize = 44000; +#if defined(AFS_HPUX_ENV) || defined(AFS_SUN_ENV) || defined(AFS_SGI51_ENV) + rx_SetStackSize(1, stackSize); +#endif + if ( udpBufSize ) + rx_SetUdpBufSize(udpBufSize);/* set the UDP buffer size for receive */ + if (rx_Init((int)htons(7000))<0) { + ViceLog(0, ("Cannot initialize RX\n")); + exit(1); + } + if (!rxJumbograms) { + /* Don't send and don't allow 3.4 clients to send jumbograms. */ + rx_SetNoJumbo(); + } + rx_GetIFInfo(); + rx_SetRxDeadTime(30); + sc[0] = rxnull_NewServerSecurityObject(); + sc[1] = 0; /* rxvab_NewServerSecurityObject(key1, 0) */ + sc[2] = rxkad_NewServerSecurityObject (rxkad_clear, NULL, + get_key, NULL); + sc[3] = rxkad_NewServerSecurityObject (rxkad_crypt, NULL, + get_key, NULL); + tservice = rx_NewService + (/* port */ 0, /* service id */ 1, /*service name */ "AFS", + /* security classes */ sc, /* numb sec classes */ 4, + RXAFS_ExecuteRequest); + if (!tservice) { + ViceLog(0, ("Failed to initialize RX, probably two servers running.\n")); + exit(-1); } - if ((i = write(fd, (char *)&FS_HostAddr_cnt, sizeof(afs_int32))) != sizeof(afs_int32)) { - ViceLog(0, ("%s: write of # of entries failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno)); - return EIO; + rx_SetDestroyConnProc(tservice, (void (*)())h_FreeConnection); + rx_SetMinProcs(tservice, 3); + rx_SetMaxProcs(tservice, lwps); + rx_SetCheckReach(tservice, 1); + + tservice = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", sc, 4, RXSTATS_ExecuteRequest); + if (!tservice) { + ViceLog(0, ("Failed to initialize rpc stat service.\n")); + exit(-1); } - for (i = 0; i < FS_HostAddr_cnt; i++) { - if (write(fd, (char *)&FS_HostAddrs[i], sizeof(afs_int32)) != sizeof(afs_int32)) { - ViceLog(0, ("%s: write of addresses failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno)); - return EIO; - } + rx_SetMinProcs(tservice, 2); + rx_SetMaxProcs(tservice, 4); + + /* + * Enable RX hot threads, which allows the listener thread to trade + * places with an idle thread and moves the context switch from listener + * to worker out of the critical path. + */ + rx_EnableHotThread(); + + /* Some rx debugging */ + if (rxlog || eventlog) { + debugFile = fopen("rx_dbg", "w"); + if (rxlog) rx_debugFile = debugFile; + if (eventlog) rxevent_debugFile = debugFile; } - close(fd); - return 0; -} -/* - * defect 10966 - * This routine sets up the buffers for the VL_RegisterAddrs RPC. All addresses - * in FS_HostAddrs[] are in NBO, while the RPC treats them as a "blob" of data - * and so we need to convert each of them into HBO which is what the extra - * array called FS_HostAddrs_HBO is used here. - */ -Do_VLRegisterRPC() { - register int code; - bulkaddrs addrs; - extern int VL_RegisterAddrs(); - afs_uint32 FS_HostAddrs_HBO[ADDRSPERSITE]; - int i=0; - - for (i=0; i < FS_HostAddr_cnt ; i++) - FS_HostAddrs_HBO[i]=ntohl(FS_HostAddrs[i]); - addrs.bulkaddrs_len = FS_HostAddr_cnt; - addrs.bulkaddrs_val = (afs_uint32 *)FS_HostAddrs_HBO; - code = ubik_Call(VL_RegisterAddrs, cstruct, 0, &FS_HostUUID, 0, &addrs); + h_InitHostPackage(); /* set up local cellname and realmname */ + InitCallBack(numberofcbs); + ClearXStatValues(); + + code = InitVL(); if (code) { - if (code == VL_MULTIPADDR) { - ViceLog(0, ("VL_RegisterAddrs rpc failed; The ethernet address exist on a different server; repair it\n")); - ViceLog(0, ("VL_RegisterAddrs rpc failed; See VLLog for details\n")); - return code; - } else if (code == RXGEN_OPCODE) { - ViceLog(0, ("vlserver doesn't support VL_RegisterAddrs rpc; ignored\n")); - FS_registered = 2; /* So we don't have to retry in the gc daemon */ - } else { - ViceLog(0, ("VL_RegisterAddrs rpc failed; will retry periodically (code=%d, err=%d)\n", - code, errno)); - } - } else { - FS_registered = 2; /* So we don't have to retry in the gc daemon */ - WriteSysIdFile(); + ViceLog(0,("Fatal error in library initialization, exiting!!\n")); + exit(1); } - return 0; -} + code = InitPR(); + if (code) { + ViceLog(0,("Fatal error in protection initialization, exiting!!\n")); + exit(1); + } -#if 0 -static int AddrsEqual(cnt, addr1, addr2) - int cnt; - afs_int32 *addr1, *addr2; -{ - register int i, j; + /* allow super users to manage RX statistics */ + rx_SetRxStatUserOk(fs_rxstat_userok); - for (i = 0; i < cnt; i++) { - for (j = 0; j < cnt; j++) { - if (addr1[i] == addr2[j]) break; - } - if (j == cnt) return 0; + rx_StartServer(0); /* now start handling requests */ + + /* we ensure that there is enough space in the vnode buffer to satisfy + ** requests from all concurrent threads. + ** the maximum number of vnodes used by a single thread at any one time + ** is three ( "link" uses three vnodes simultaneously, one vLarge and + ** two vSmall for linking files and two vLarge and one vSmall for linking + ** files ) : dhruba + */ + minVnodesRequired = 2 * lwps + 1; + if ( minVnodesRequired > nSmallVns ) { + nSmallVns = minVnodesRequired; + ViceLog(0, ("Overriding -s command line parameter with %d\n", + nSmallVns)); + } + if ( minVnodesRequired > large ) { + large = minVnodesRequired; + ViceLog(0, ("Overriding -l command line parameter with %d\n", large)); } - return 1; -} -#endif -InitVL() { - int (*old)(); - afs_int32 code; - afs_int32 cnt, i; - extern int rxi_numNetAddrs; - extern afs_uint32 rxi_NetAddrs[]; + /* We now do this after getting the listener up and running, so that client + connections don't timeout (maybe) if a file server is restarted, since it + will be available "real soon now". Worry about whether we can satisfy the + calls in the volume package itself. + */ + if (VInitVolumePackage(fileServer,large,nSmallVns,0, volcache)) { + ViceLog(0, ("Shutting down: errors encountered initializing volume package\n")); + VShutdown(); + exit(1); + } /* - * If this fails, it's because something major is wrong, and is not - * likely to be time dependent. + * We are done calling fopen/fdopen. It is safe to use a large + * of the file descriptor cache. */ - code = vl_Initialize(AFSDIR_SERVER_ETC_DIRPATH); - if (code != 0) { - ViceLog(0, ("Couldn't initialize protection library; code=%d.\n", code)); - return code; + ih_UseLargeCache(); + +#ifdef AFS_PTHREAD_ENV + assert(pthread_attr_init(&tattr) == 0); + assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0); + /* Block signals in the threads */ + AFS_SIGSET_CLEAR(); + assert(pthread_create(&serverPid, &tattr, (void *)FiveMinuteCheckLWP, &fiveminutes) == 0); + assert(pthread_create(&serverPid, &tattr, (void *)HostCheckLWP, &fiveminutes) == 0); + AFS_SIGSET_RESTORE(); +#else /* AFS_PTHREAD_ENV */ + assert(LWP_CreateProcess(FiveMinuteCheckLWP, stack*1024, LWP_MAX_PRIORITY - 2, + (void *) &fiveminutes, "FiveMinuteChecks", &serverPid) == LWP_SUCCESS); + + assert(LWP_CreateProcess(HostCheckLWP, stack*1024, LWP_MAX_PRIORITY - 2, + (void *) &fiveminutes, "HostCheck", &serverPid) == LWP_SUCCESS); +#endif /* AFS_PTHREAD_ENV */ + + TM_GetTimeOfDay(&tp, 0); + +#ifndef AFS_QUIETFS_ENV + if (console != NULL) { + fprintf(console, "File server has started at %s\r", + afs_ctime(&tp.tv_sec, tbuffer, sizeof(tbuffer))); } +#endif - /* Read or create the sysid file and register the fileserver's - * IP addresses with the vlserver. + /* + * Figure out the FileServer's name and primary address. */ - code = ReadSysIdFile(); + ViceLog(0, ("Getting FileServer name...\n")); + code = gethostname(FS_HostName, 64); if (code) { - /* Need to create the file */ - ViceLog(0, ("Creating new SysID file\n")); - if ((code = afs_uuid_create(&FS_HostUUID))) { - ViceLog(0, ("Failed to create new uuid: %d\n", code)); - exit(1); - } + ViceLog(0, ("gethostname() failed\n")); } - /* A good sysid file exists; inform the vlserver. If any conflicts, - * we always use the latest interface available as the real truth. - */ -#ifndef AFS_NT40_ENV - if(AFSDIR_SERVER_NETRESTRICT_FILEPATH || AFSDIR_SERVER_NETINFO_FILEPATH) { - /* - * Find addresses we are supposed to register as per the netrestrict - * and netinfo files (/usr/afs/local/NetInfo and - * /usr/afs/local/NetRestict) - */ - char reason[1024]; - afs_int32 code = parseNetFiles(FS_HostAddrs,NULL, NULL, - ADDRSPERSITE, reason, - AFSDIR_SERVER_NETINFO_FILEPATH, - AFSDIR_SERVER_NETRESTRICT_FILEPATH); - if (code < 0) { - ViceLog(0,("Can't register any valid addresses: %s\n",reason)); - exit(1); - } - FS_HostAddr_cnt = (afs_uint32) code; + ViceLog(0, ("FileServer host name is '%s'\n", FS_HostName)); + + ViceLog(0, ("Getting FileServer address...\n")); + he = gethostbyname(FS_HostName); + if (!he) { + ViceLog(0, ("Can't find address for FileServer '%s'\n", FS_HostName)); } - else + else { + char hoststr[16]; + memcpy(&FS_HostAddr_NBO, he->h_addr, 4); + afs_inet_ntoa_r(FS_HostAddr_NBO, hoststr); + FS_HostAddr_HBO = ntohl(FS_HostAddr_NBO); + ViceLog(0,("FileServer %s has address %s (0x%x or 0x%x in host byte order)\n", + FS_HostName, hoststr, FS_HostAddr_NBO, FS_HostAddr_HBO)); + } + + /* Install handler to catch the shutdown signal */ + signal(SIGQUIT, ShutDown_Signal); /* bosserver assumes SIGQUIT shutdown */ + + ViceLog(0,("File Server started %s", + afs_ctime(&tp.tv_sec, tbuffer, sizeof(tbuffer)))); +#if FS_STATS_DETAILED + afs_FullPerfStats.det.epoch.tv_sec = StartTime = tp.tv_sec; #endif - { - FS_HostAddr_cnt = rx_getAllAddr(FS_HostAddrs, ADDRSPERSITE); +#ifdef AFS_PTHREAD_ENV + while(1) { + sleep(1000); /* long time */ } +#else /* AFS_PTHREAD_ENV */ + assert(LWP_WaitProcess(&parentPid) == LWP_SUCCESS); +#endif /* AFS_PTHREAD_ENV */ +} - FS_registered = 1; - code = Do_VLRegisterRPC(); - return code; -} -- 2.39.5