Index: openafs/src/WINNT/afsclass/afsclassfn.cpp diff -c openafs/src/WINNT/afsclass/afsclassfn.cpp:1.6 openafs/src/WINNT/afsclass/afsclassfn.cpp:1.6.4.1 *** openafs/src/WINNT/afsclass/afsclassfn.cpp:1.6 Sat Nov 5 01:47:44 2005 --- openafs/src/WINNT/afsclass/afsclassfn.cpp Thu Jul 19 11:56:53 2007 *************** *** 51,59 **** AfsClass_Enter(); NOTIFYCALLBACK::SendNotificationToAll (evtGetServerLogFileBegin, lpiServer, pszRemote, 0); ! PVOID hCell; ! PVOID hBOS; ! LPSERVER lpServer; if ((lpServer = lpiServer->OpenServer (&status)) == NULL) rc = FALSE; else --- 51,59 ---- AfsClass_Enter(); NOTIFYCALLBACK::SendNotificationToAll (evtGetServerLogFileBegin, lpiServer, pszRemote, 0); ! PVOID hCell = NULL; ! PVOID hBOS = NULL; ! LPSERVER lpServer = NULL; if ((lpServer = lpiServer->OpenServer (&status)) == NULL) rc = FALSE; else *************** *** 387,394 **** AfsClass_Enter(); NOTIFYCALLBACK::SendNotificationToAll (evtRestartServiceBegin, lpiRestart); ! PVOID hCell; ! PVOID hBOS; LPSERVER lpServer; if ((lpServer = lpiRestart->OpenServer (&status)) == NULL) rc = FALSE; --- 387,394 ---- AfsClass_Enter(); NOTIFYCALLBACK::SendNotificationToAll (evtRestartServiceBegin, lpiRestart); ! PVOID hCell = NULL; ! PVOID hBOS = NULL; LPSERVER lpServer; if ((lpServer = lpiRestart->OpenServer (&status)) == NULL) rc = FALSE; *************** *** 489,497 **** // Obtain hCell and hVOS // ! PVOID hCell; PVOID hVOS = NULL; ! LPSERVER lpServer; if ((lpServer = lpiAggregate->OpenServer (&status)) == NULL) rc = FALSE; else --- 489,497 ---- // Obtain hCell and hVOS // ! PVOID hCell = NULL; PVOID hVOS = NULL; ! LPSERVER lpServer = NULL; if ((lpServer = lpiAggregate->OpenServer (&status)) == NULL) rc = FALSE; else *************** *** 603,611 **** // Obtain hCell and hVOS // ! PVOID hCell; PVOID hVOS = NULL; ! LPSERVER lpServer; if ((lpServer = lpiFileset->OpenServer (&status)) == NULL) rc = FALSE; else --- 603,611 ---- // Obtain hCell and hVOS // ! PVOID hCell = NULL; PVOID hVOS = NULL; ! LPSERVER lpServer = NULL; if ((lpServer = lpiFileset->OpenServer (&status)) == NULL) rc = FALSE; else *************** *** 1151,1157 **** lpServer->Close(); } - LPCELL lpCell; if ((lpCell = lpiServer->OpenCell (&status)) == NULL) rc = FALSE; else --- 1151,1156 ---- Index: openafs/src/WINNT/afsclass/c_svr.cpp diff -c openafs/src/WINNT/afsclass/c_svr.cpp:1.5 openafs/src/WINNT/afsclass/c_svr.cpp:1.5.4.1 *** openafs/src/WINNT/afsclass/c_svr.cpp:1.5 Sat Nov 5 01:47:44 2005 --- openafs/src/WINNT/afsclass/c_svr.cpp Thu Jul 19 11:56:53 2007 *************** *** 783,790 **** // the lpServer pointer won't have been freed.) // PVOID hCell; ! PVOID hBOS; ! PVOID hVOS; TCHAR szServer[ cchNAME ]; --- 783,790 ---- // the lpServer pointer won't have been freed.) // PVOID hCell; ! PVOID hBOS = NULL; ! PVOID hVOS = NULL; TCHAR szServer[ cchNAME ]; Index: openafs/src/WINNT/afsd/cm_buf.c diff -c openafs/src/WINNT/afsd/cm_buf.c:1.31.2.16 openafs/src/WINNT/afsd/cm_buf.c:1.31.2.18 *** openafs/src/WINNT/afsd/cm_buf.c:1.31.2.16 Sun Jun 10 13:00:07 2007 --- openafs/src/WINNT/afsd/cm_buf.c Thu Aug 9 01:33:56 2007 *************** *** 593,598 **** --- 593,599 ---- long code = 0; long isdirty = 0; cm_scache_t * scp = NULL; + osi_hyper_t offset; osi_assert(bp->magic == CM_BUF_MAGIC); *************** *** 603,611 **** scp = cm_FindSCache(&bp->fid); if (scp) { osi_Log2(buf_logp, "buf_CleanAsyncLocked starts I/O on scp 0x%p buf 0x%p", scp, bp); ! code = (*cm_buf_opsp->Writep)(scp, &bp->offset, ! cm_data.buf_blockSize, 0, bp->userp, ! reqp); osi_Log3(buf_logp, "buf_CleanAsyncLocked I/O on scp 0x%p buf 0x%p, done=%d", scp, bp, code); cm_ReleaseSCache(scp); --- 604,613 ---- scp = cm_FindSCache(&bp->fid); if (scp) { osi_Log2(buf_logp, "buf_CleanAsyncLocked starts I/O on scp 0x%p buf 0x%p", scp, bp); ! ! offset = bp->offset; ! LargeIntegerAdd(offset, ConvertLongToLargeInteger(bp->dirty_offset)); ! code = (*cm_buf_opsp->Writep)(scp, &offset, bp->dirty_length, 0, bp->userp, reqp); osi_Log3(buf_logp, "buf_CleanAsyncLocked I/O on scp 0x%p buf 0x%p, done=%d", scp, bp, code); cm_ReleaseSCache(scp); *************** *** 623,628 **** --- 625,632 ---- if (code == CM_ERROR_NOSUCHFILE){ bp->flags &= ~CM_BUF_DIRTY; bp->flags |= CM_BUF_ERROR; + bp->dirty_offset = 0; + bp->dirty_length = 0; bp->error = CM_ERROR_NOSUCHFILE; bp->dataVersion = -1; /* bad */ bp->dirtyCounter++; *************** *** 1034,1045 **** /* load the page; freshly created pages should be idle */ osi_assert(!(bp->flags & (CM_BUF_READING | CM_BUF_WRITING))); - /* setup offset, event */ - #ifndef DJGPP /* doesn't seem to be used */ - bp->over.Offset = bp->offset.LowPart; - bp->over.OffsetHigh = bp->offset.HighPart; - #endif /* !DJGPP */ - /* start the I/O; may drop lock */ bp->flags |= CM_BUF_READING; code = (*cm_buf_opsp->Readp)(bp, cm_data.buf_blockSize, &tcount, NULL); --- 1038,1043 ---- *************** *** 1174,1215 **** * * The buffer must be locked before calling this routine. */ ! void buf_SetDirty(cm_buf_t *bp) { osi_assert(bp->magic == CM_BUF_MAGIC); osi_assert(bp->refCount > 0); ! if (bp->flags & CM_BUF_DIRTY) { osi_Log1(buf_logp, "buf_SetDirty 0x%p already dirty", bp); } else { osi_Log1(buf_logp, "buf_SetDirty 0x%p", bp); - } - /* set dirty bit */ - bp->flags |= CM_BUF_DIRTY; ! /* and turn off EOF flag, since it has associated data now */ ! bp->flags &= ~CM_BUF_EOF; ! /* and add to the dirty list. ! * we obtain a hold on the buffer for as long as it remains ! * in the list. buffers are only removed from the list by ! * the buf_IncrSyncer function regardless of when else the ! * dirty flag might be cleared. ! * ! * This should never happen but just in case there is a bug ! * elsewhere, never add to the dirty list if the buffer is ! * already there. ! */ ! lock_ObtainWrite(&buf_globalLock); ! if (bp->dirtyp == NULL && cm_data.buf_dirtyListEndp != bp) { ! buf_HoldLocked(bp); ! if (!cm_data.buf_dirtyListp) { ! cm_data.buf_dirtyListp = cm_data.buf_dirtyListEndp = bp; ! } else { ! cm_data.buf_dirtyListEndp->dirtyp = bp; ! cm_data.buf_dirtyListEndp = bp; ! } ! bp->dirtyp = NULL; } lock_ReleaseWrite(&buf_globalLock); } --- 1172,1233 ---- * * The buffer must be locked before calling this routine. */ ! void buf_SetDirty(cm_buf_t *bp, afs_uint32 offset, afs_uint32 length) { osi_assert(bp->magic == CM_BUF_MAGIC); osi_assert(bp->refCount > 0); ! ! lock_ObtainWrite(&buf_globalLock); if (bp->flags & CM_BUF_DIRTY) { + osi_Log1(buf_logp, "buf_SetDirty 0x%p already dirty", bp); + + if (bp->dirty_offset <= offset) { + if (bp->dirty_offset + bp->dirty_length >= offset + length) { + /* dirty_length remains the same */ + } else { + bp->dirty_length = offset + length - bp->dirty_offset; + } + } else /* bp->dirty_offset > offset */ { + if (bp->dirty_offset + bp->dirty_length >= offset + length) { + bp->dirty_length = bp->dirty_offset + bp->dirty_length - offset; + } else { + bp->dirty_length = length; + } + bp->dirty_offset = offset; + } } else { osi_Log1(buf_logp, "buf_SetDirty 0x%p", bp); ! /* set dirty bit */ ! bp->flags |= CM_BUF_DIRTY; ! /* and turn off EOF flag, since it has associated data now */ ! bp->flags &= ~CM_BUF_EOF; ! ! bp->dirty_offset = offset; ! bp->dirty_length = length; ! ! /* and add to the dirty list. ! * we obtain a hold on the buffer for as long as it remains ! * in the list. buffers are only removed from the list by ! * the buf_IncrSyncer function regardless of when else the ! * dirty flag might be cleared. ! * ! * This should never happen but just in case there is a bug ! * elsewhere, never add to the dirty list if the buffer is ! * already there. ! */ ! if (bp->dirtyp == NULL && cm_data.buf_dirtyListEndp != bp) { ! buf_HoldLocked(bp); ! if (!cm_data.buf_dirtyListp) { ! cm_data.buf_dirtyListp = cm_data.buf_dirtyListEndp = bp; ! } else { ! cm_data.buf_dirtyListEndp->dirtyp = bp; ! cm_data.buf_dirtyListEndp = bp; ! } ! bp->dirtyp = NULL; ! } } lock_ReleaseWrite(&buf_globalLock); } *************** *** 1392,1397 **** --- 1410,1417 ---- if (LargeIntegerLessThanOrEqualTo(*sizep, bufp->offset)) { /* truncating the entire page */ bufp->flags &= ~CM_BUF_DIRTY; + bufp->dirty_offset = 0; + bufp->dirty_length = 0; bufp->dataVersion = -1; /* known bad */ bufp->dirtyCounter++; } *************** *** 1511,1516 **** --- 1531,1564 ---- return code; } + /* Must be called with scp->mx held */ + long buf_ForceDataVersion(cm_scache_t * scp, afs_uint32 fromVersion, afs_uint32 toVersion) + { + cm_buf_t * bp; + cm_buf_t * nbp; + unsigned int i; + int found = 0; + + i = BUF_FILEHASH(&scp->fid); + + lock_ObtainWrite(&buf_globalLock); + + for (bp = cm_data.buf_fileHashTablepp[i]; bp; bp = bp->fileHashp) { + if (cm_FidCmp(&bp->fid, &scp->fid) == 0) { + if (bp->dataVersion == fromVersion) { + bp->dataVersion = toVersion; + found = 1; + } + } + } + lock_ReleaseWrite(&buf_globalLock); + + if (found) + return 0; + else + return ENOENT; + } + long buf_CleanVnode(struct cm_scache *scp, cm_user_t *userp, cm_req_t *reqp) { long code = 0; *************** *** 1702,1709 **** { cm_buf_t *bp; afs_uint32 bcount = 0; ! for (bp = cm_data.buf_allp; bp; bp=bp->allp, bcount++) { if (!cm_FidCmp(fidp, &bp->fid) && (bp->flags & CM_BUF_DIRTY)) return 1; } --- 1750,1760 ---- { cm_buf_t *bp; afs_uint32 bcount = 0; + afs_uint32 i; ! i = BUF_FILEHASH(fidp); ! ! for (bp = cm_data.buf_fileHashTablepp[i]; bp; bp=bp->allp, bcount++) { if (!cm_FidCmp(fidp, &bp->fid) && (bp->flags & CM_BUF_DIRTY)) return 1; } *************** *** 1723,1728 **** --- 1774,1781 ---- lock_ObtainMutex(&bp->mx); bp->cmFlags &= ~CM_BUF_CMSTORING; bp->flags &= ~CM_BUF_DIRTY; + bp->dirty_offset = 0; + bp->dirty_length = 0; bp->flags |= CM_BUF_ERROR; bp->error = VNOVNODE; bp->dataVersion = -1; /* bad */ Index: openafs/src/WINNT/afsd/cm_buf.h diff -c openafs/src/WINNT/afsd/cm_buf.h:1.12.4.4 openafs/src/WINNT/afsd/cm_buf.h:1.12.4.6 *** openafs/src/WINNT/afsd/cm_buf.h:1.12.4.4 Sun Feb 4 22:41:41 2007 --- openafs/src/WINNT/afsd/cm_buf.h Thu Aug 9 01:33:56 2007 *************** *** 72,106 **** long dirtyCounter; /* bumped at each dirty->clean transition */ osi_hyper_t offset; /* offset */ cm_fid_t fid; /* file ID */ - #ifdef DEBUG - cm_scache_t *scp; /* for debugging, the scache object belonging to */ - /* the fid at the time of fid assignment. */ - #endif long flags; /* flags we're using */ char *datap; /* data in this buffer */ unsigned long error; /* last error code, if CM_BUF_ERROR is set */ cm_user_t *userp; /* user who wrote to the buffer last */ - #ifndef DJGPP - OVERLAPPED over; /* overlapped structure for I/O */ - #endif /* fields added for the CM; locked by scp->mx */ long dataVersion; /* data version of this page */ long cmFlags; /* flags for cm */ #ifdef DISKCACHE95 cm_diskcache_t *dcp; /* diskcache structure */ #endif /* DISKCACHE95 */ ! ! /* syncop state */ ! afs_uint32 waitCount; /* number of threads waiting */ ! afs_uint32 waitRequests; /* num of thread wait requests */ } cm_buf_t; /* values for cmFlags */ #define CM_BUF_CMFETCHING 1 /* fetching this buffer */ #define CM_BUF_CMSTORING 2 /* storing this buffer */ #define CM_BUF_CMFULLYFETCHED 4 /* read-while-fetching optimization */ ! /* waiting is done based on scp->flags */ /* represents soft reference which is OK to lose on a recycle */ typedef struct cm_softRef { --- 72,111 ---- long dirtyCounter; /* bumped at each dirty->clean transition */ osi_hyper_t offset; /* offset */ cm_fid_t fid; /* file ID */ long flags; /* flags we're using */ char *datap; /* data in this buffer */ unsigned long error; /* last error code, if CM_BUF_ERROR is set */ cm_user_t *userp; /* user who wrote to the buffer last */ /* fields added for the CM; locked by scp->mx */ long dataVersion; /* data version of this page */ long cmFlags; /* flags for cm */ + + /* syncop state */ + afs_uint32 waitCount; /* number of threads waiting */ + afs_uint32 waitRequests; /* num of thread wait requests */ + + afs_uint32 dirty_offset; /* offset from beginning of buffer containing dirty bytes */ + afs_uint32 dirty_length; /* number of dirty bytes within the buffer */ + #ifdef DISKCACHE95 cm_diskcache_t *dcp; /* diskcache structure */ #endif /* DISKCACHE95 */ ! #ifdef DEBUG ! cm_scache_t *scp; /* for debugging, the scache object belonging to */ ! /* the fid at the time of fid assignment. */ ! #else ! void * dummy; ! #endif } cm_buf_t; /* values for cmFlags */ #define CM_BUF_CMFETCHING 1 /* fetching this buffer */ #define CM_BUF_CMSTORING 2 /* storing this buffer */ #define CM_BUF_CMFULLYFETCHED 4 /* read-while-fetching optimization */ ! #define CM_BUF_CMWRITING 8 /* writing to this buffer */ ! /* waiting is done based on scp->flags. Removing bits from cmFlags ! should be followed by waking the scp. */ /* represents soft reference which is OK to lose on a recycle */ typedef struct cm_softRef { *************** *** 161,167 **** extern void buf_CleanWait(cm_scache_t *, cm_buf_t *); ! extern void buf_SetDirty(cm_buf_t *); extern long buf_CleanAndReset(void); --- 166,172 ---- extern void buf_CleanWait(cm_scache_t *, cm_buf_t *); ! extern void buf_SetDirty(cm_buf_t *, afs_uint32 offset, afs_uint32 length); extern long buf_CleanAndReset(void); *************** *** 196,201 **** --- 201,208 ---- extern long buf_CleanDirtyBuffers(cm_scache_t *scp); + extern long buf_ForceDataVersion(cm_scache_t * scp, afs_uint32 fromVersion, afs_uint32 toVersion); + /* error codes */ #define CM_BUF_EXISTS 1 /* buffer exists, and shouldn't */ #endif /* _BUF_H__ENV_ */ Index: openafs/src/WINNT/afsd/cm_callback.c diff -c openafs/src/WINNT/afsd/cm_callback.c:1.41.4.17 openafs/src/WINNT/afsd/cm_callback.c:1.41.4.18 *** openafs/src/WINNT/afsd/cm_callback.c:1.41.4.17 Sat Jul 7 09:38:33 2007 --- openafs/src/WINNT/afsd/cm_callback.c Thu Aug 2 16:46:12 2007 *************** *** 1756,1767 **** return code; } /* called periodically by cm_daemon to shut down use of expired callbacks */ void cm_CheckCBExpiration(void) { int i; cm_scache_t *scp; ! time_t now; osi_Log0(afsd_logp, "CheckCBExpiration"); --- 1756,1807 ---- return code; } + + /* called with cm_scacheLock held */ + long cm_CBServersUp(cm_scache_t *scp, time_t * downTime) + { + cm_vol_state_t *statep; + cm_volume_t * volp = scp->volp; + afs_uint32 volID = scp->fid.volume; + cm_serverRef_t *tsrp; + int found; + + *downTime = 0; + + if (scp->cbServerp == NULL) + return 1; + + if (volp->rw.ID == volID) { + statep = &volp->rw; + } else if (volp->ro.ID == volID) { + statep = &volp->ro; + } else if (volp->bk.ID == volID) { + statep = &volp->bk; + } + + if (statep->state == vl_online) + return 1; + + for (found = 0,tsrp = statep->serversp; tsrp; tsrp=tsrp->next) { + if (tsrp->server == scp->cbServerp) + found = 1; + if (tsrp->server->downTime > *downTime) + *downTime = tsrp->server->downTime; + } + + /* if the cbServerp does not match the current volume server list + * we report the callback server as up so the callback can be + * expired. + */ + return(found ? 0 : 1); + } + /* called periodically by cm_daemon to shut down use of expired callbacks */ void cm_CheckCBExpiration(void) { int i; cm_scache_t *scp; ! time_t now, downTime = 0; osi_Log0(afsd_logp, "CheckCBExpiration"); *************** *** 1769,1786 **** lock_ObtainWrite(&cm_scacheLock); for (i=0; inextp) { ! cm_HoldSCacheNoLock(scp); ! if (scp->cbExpires > 0 && (scp->cbServerp == NULL || now > scp->cbExpires)) { lock_ReleaseWrite(&cm_scacheLock); ! osi_Log4(afsd_logp, "Callback Expiration Discarding SCache scp 0x%p vol %u vn %u uniq %u", scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique); lock_ObtainMutex(&scp->mx); cm_DiscardSCache(scp); lock_ReleaseMutex(&scp->mx); cm_CallbackNotifyChange(scp); lock_ObtainWrite(&cm_scacheLock); } - cm_ReleaseSCacheNoLock(scp); } } lock_ReleaseWrite(&cm_scacheLock); --- 1809,1831 ---- lock_ObtainWrite(&cm_scacheLock); for (i=0; inextp) { ! ! if (scp->cbServerp && scp->cbExpires > 0 && now > scp->cbExpires && ! (cm_CBServersUp(scp, &downTime) || downTime == 0 || downTime >= scp->cbExpires)) ! { ! cm_HoldSCacheNoLock(scp); lock_ReleaseWrite(&cm_scacheLock); ! ! osi_Log4(afsd_logp, "Callback Expiration Discarding SCache scp 0x%p vol %u vn %u uniq %u", scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique); lock_ObtainMutex(&scp->mx); cm_DiscardSCache(scp); lock_ReleaseMutex(&scp->mx); cm_CallbackNotifyChange(scp); + + cm_ReleaseSCacheNoLock(scp); lock_ObtainWrite(&cm_scacheLock); } } } lock_ReleaseWrite(&cm_scacheLock); Index: openafs/src/WINNT/afsd/cm_config.h diff -c openafs/src/WINNT/afsd/cm_config.h:1.8 openafs/src/WINNT/afsd/cm_config.h:1.8.6.1 *** openafs/src/WINNT/afsd/cm_config.h:1.8 Fri Mar 11 00:33:22 2005 --- openafs/src/WINNT/afsd/cm_config.h Thu Aug 9 01:33:56 2007 *************** *** 13,19 **** #define CM_CONFIGDEFAULT_CACHESIZE 98304 #define CM_CONFIGDEFAULT_BLOCKSIZE 4096 #define CM_CONFIGDEFAULT_STATS 10000 ! #define CM_CONFIGDEFAULT_CHUNKSIZE 17 #define CM_CONFIGDEFAULT_DAEMONS 2 #define CM_CONFIGDEFAULT_SVTHREADS 25 #define CM_CONFIGDEFAULT_TRACEBUFSIZE 5000 --- 13,19 ---- #define CM_CONFIGDEFAULT_CACHESIZE 98304 #define CM_CONFIGDEFAULT_BLOCKSIZE 4096 #define CM_CONFIGDEFAULT_STATS 10000 ! #define CM_CONFIGDEFAULT_CHUNKSIZE 20 #define CM_CONFIGDEFAULT_DAEMONS 2 #define CM_CONFIGDEFAULT_SVTHREADS 25 #define CM_CONFIGDEFAULT_TRACEBUFSIZE 5000 Index: openafs/src/WINNT/afsd/cm_conn.c diff -c openafs/src/WINNT/afsd/cm_conn.c:1.49.2.19 openafs/src/WINNT/afsd/cm_conn.c:1.49.2.21 *** openafs/src/WINNT/afsd/cm_conn.c:1.49.2.19 Mon Jun 25 00:59:40 2007 --- openafs/src/WINNT/afsd/cm_conn.c Tue Aug 7 00:00:49 2007 *************** *** 551,559 **** else if (errorCode >= -64 && errorCode < 0) { /* mark server as down */ lock_ObtainMutex(&serverp->mx); ! if (reqp->flags & CM_REQ_NEW_CONN_FORCED) serverp->flags |= CM_SERVERFLAG_DOWN; ! else { reqp->flags |= CM_REQ_NEW_CONN_FORCED; forcing_new = 1; } --- 551,560 ---- else if (errorCode >= -64 && errorCode < 0) { /* mark server as down */ lock_ObtainMutex(&serverp->mx); ! if (reqp->flags & CM_REQ_NEW_CONN_FORCED) { serverp->flags |= CM_SERVERFLAG_DOWN; ! serverp->downTime = osi_Time(); ! } else { reqp->flags |= CM_REQ_NEW_CONN_FORCED; forcing_new = 1; } *************** *** 708,720 **** struct timeval now; #endif /* DJGPP */ if (serversp == NULL) { osi_Log1(afsd_logp, "cm_ConnByMServers returning 0x%x", CM_ERROR_ALLDOWN); return CM_ERROR_ALLDOWN; } - *connpp = NULL; - #ifndef DJGPP timeUsed = (GetTickCount() - reqp->startTime) / 1000; #else --- 709,721 ---- struct timeval now; #endif /* DJGPP */ + *connpp = NULL; + if (serversp == NULL) { osi_Log1(afsd_logp, "cm_ConnByMServers returning 0x%x", CM_ERROR_ALLDOWN); return CM_ERROR_ALLDOWN; } #ifndef DJGPP timeUsed = (GetTickCount() - reqp->startTime) / 1000; #else *************** *** 867,872 **** --- 868,875 ---- cm_conn_t *tcp; cm_ucell_t *ucellp; + *connpp = NULL; + lock_ObtainMutex(&userp->mx); lock_ObtainWrite(&cm_connLock); for (tcp = serverp->connsp; tcp; tcp=tcp->nextp) { Index: openafs/src/WINNT/afsd/cm_dcache.c diff -c openafs/src/WINNT/afsd/cm_dcache.c:1.30.2.15 openafs/src/WINNT/afsd/cm_dcache.c:1.30.2.16 *** openafs/src/WINNT/afsd/cm_dcache.c:1.30.2.15 Sun Jun 10 13:00:07 2007 --- openafs/src/WINNT/afsd/cm_dcache.c Thu Aug 9 01:33:56 2007 *************** *** 1254,1261 **** } if (failed) bufp->flags &= ~CM_BUF_WRITING; ! else bufp->flags &= ~(CM_BUF_WRITING | CM_BUF_DIRTY); } lock_ReleaseMutex(&scp->mx); --- 1254,1263 ---- } if (failed) bufp->flags &= ~CM_BUF_WRITING; ! else { bufp->flags &= ~(CM_BUF_WRITING | CM_BUF_DIRTY); + bufp->dirty_offset = bufp->dirty_length = 0; + } } lock_ReleaseMutex(&scp->mx); Index: openafs/src/WINNT/afsd/cm_dir.c diff -c openafs/src/WINNT/afsd/cm_dir.c:1.4.4.1 openafs/src/WINNT/afsd/cm_dir.c:1.4.4.2 *** openafs/src/WINNT/afsd/cm_dir.c:1.4.4.1 Sat Jun 24 16:41:54 2006 --- openafs/src/WINNT/afsd/cm_dir.c Thu Aug 2 16:53:51 2007 *************** *** 20,33 **** #include /* compute how many 32 byte entries an AFS 3 dir requires for storing * the specified name. */ ! long cm_NameEntries(char *namep, long *lenp) { long i; ! i = (long)strlen(namep); if (lenp) *lenp = i; ! return 1+((i+16)>>5); } --- 20,1437 ---- #include + afs_int32 DErrno; + + /* Local static prototypes */ + static long + cm_DirGetBlob(cm_dirOp_t * op, + unsigned int blobno, cm_buf_t ** bufferpp, cm_dirEntry_t ** blobpp); + + static long + cm_DirFindItem(cm_dirOp_t * op, + char *ename, + cm_buf_t ** itembufpp, cm_dirEntry_t ** itempp, + cm_buf_t ** prevbufpp, unsigned short **previtempp); + + static long + cm_DirOpAddBuffer(cm_dirOp_t * op, cm_buf_t * buffer); + + /* flags for cm_DirOpDelBuffer */ + #define DIROP_MODIFIED 1 + #define DIROP_SCPLOCKED 2 + + static int + cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * buffer, int flags); + + static long + cm_DirCheckStatus(cm_dirOp_t * op); + + static long + cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified); + + static long + cm_DirGetPage(cm_dirOp_t * op, + long index, cm_buf_t ** bufferpp, void ** datapp); + + static long + cm_DirFindBlobs(cm_dirOp_t * op, int nblobs); + + static long + cm_DirAddPage(cm_dirOp_t * op, int pageno); + + static long + cm_DirFreeBlobs(cm_dirOp_t * op, int firstblob, int nblobs); + + /* compute how many 32 byte entries an AFS 3 dir requires for storing * the specified name. */ ! long ! cm_NameEntries(char *namep, long *lenp) { long i; ! i = (long)strlen(namep) + 1; if (lenp) *lenp = i; ! return 1 + ((i+15) >> 5); ! } ! ! /* Create an entry in a file. Dir is a file representation, while ! entry is a string name. ! ! On entry: ! op->scp->mx is locked ! ! On exit: ! op->scp->mx is locked ! ! None of the directory buffers for op->scp should be locked by the ! calling thread. ! */ ! long ! cm_DirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid) ! { ! int blobs, firstelt; ! int i; ! ! cm_dirEntry_t *ep = NULL; ! cm_buf_t *entrybuf = NULL; ! ! unsigned short *pp = NULL; ! cm_buf_t *prevptrbuf = NULL; ! ! cm_dirHeader_t *dhp = NULL; ! cm_buf_t *dhpbuf = NULL; ! ! long code = 0; ! ! /* check name quality */ ! if (*entry == 0) ! return EINVAL; ! ! osi_Log4(afsd_logp, "cm_DirCreateEntry for op 0x%p, name [%s] and fid[%d,%d]", ! op, osi_LogSaveString(afsd_logp, entry), cfid->vnode, cfid->unique); ! ! /* First check if file already exists. */ ! code = cm_DirFindItem(op, ! entry, ! &entrybuf, &ep, ! &prevptrbuf, &pp); ! if (code == 0) { ! cm_DirReleasePage(op, &entrybuf, FALSE); ! cm_DirReleasePage(op, &prevptrbuf, FALSE); ! return EEXIST; ! } ! ! blobs = cm_NameEntries(entry, NULL); /* number of entries required */ ! firstelt = cm_DirFindBlobs(op, blobs); ! if (firstelt < 0) { ! osi_Log0(afsd_logp, "cm_DirCreateEntry returning EFBIG"); ! return EFBIG; /* directory is full */ ! } ! ! /* First, we fill in the directory entry. */ ! code = cm_DirGetBlob(op, firstelt, &entrybuf, &ep); ! if (code != 0) ! return EIO; ! ! ep->flag = CM_DIR_FFIRST; ! ep->fid.vnode = htonl(cfid->vnode); ! ep->fid.unique = htonl(cfid->unique); ! strcpy(ep->name, entry); ! ! /* Now we just have to thread it on the hash table list. */ ! code = cm_DirGetPage(op, 0, &dhpbuf, &dhp); ! if (code != 0) { ! cm_DirReleasePage(op, &entrybuf, TRUE); ! return EIO; ! } ! ! i = cm_DirHash(entry); ! ! ep->next = dhp->hashTable[i]; ! dhp->hashTable[i] = htons(firstelt); ! ! cm_DirReleasePage(op, &dhpbuf, TRUE); ! cm_DirReleasePage(op, &entrybuf, TRUE); ! ! osi_Log0(afsd_logp, "cm_DirCreateEntry returning success"); ! ! return 0; ! } ! ! /* Return the length of a directory in pages ! ! On entry: ! op->scp->mx is locked ! ! On exit: ! op->scp->mx is locked ! ! The first directory page for op->scp should not be locked by the ! calling thread. ! */ ! int ! cm_DirLength(cm_dirOp_t * op) ! { ! int i, ctr; ! cm_dirHeader_t *dhp = NULL; ! cm_buf_t *dhpbuf = NULL; ! ! long code; ! ! code = cm_DirGetPage(op, 0, &dhpbuf, &dhp); ! if (code != 0) ! return 0; ! ! if (dhp->header.pgcount != 0) ! ctr = ntohs(dhp->header.pgcount); ! else { ! /* old style, count the pages */ ! ctr = 0; ! for (i = 0; i < CM_DIR_MAXPAGES; i++) ! if (dhp->alloMap[i] != CM_DIR_EPP) ! ctr++; ! } ! cm_DirReleasePage(op, &dhpbuf, FALSE); ! return ctr * CM_DIR_PAGESIZE; ! } ! ! /* Delete a directory entry. ! ! On entry: ! op->scp->mx is locked ! ! On exit: ! op->scp->mx is locked ! ! None of the directory buffers for op->scp should be locked by the ! calling thread. ! */ ! int ! cm_DirDeleteEntry(cm_dirOp_t * op, char *entry) ! { ! /* Delete an entry from a directory, including update of all free ! entry descriptors. */ ! ! int nitems, index; ! cm_dirEntry_t *firstitem = NULL; ! cm_buf_t *itembuf = NULL; ! unsigned short *previtem = NULL; ! cm_buf_t *pibuf = NULL; ! osi_hyper_t thyper; ! unsigned long junk; ! ! long code; ! ! osi_Log2(afsd_logp, "cm_DirDeleteEntry for op 0x%p, entry [%s]", ! op, osi_LogSaveString(afsd_logp, entry)); ! ! code = cm_DirFindItem(op, entry, ! &itembuf, &firstitem, ! &pibuf, &previtem); ! if (code != 0) { ! osi_Log0(afsd_logp, "cm_DirDeleteEntry returning ENOENT"); ! return ENOENT; ! } ! ! *previtem = firstitem->next; ! cm_DirReleasePage(op, &pibuf, TRUE); ! ! thyper = itembuf->offset; ! thyper = LargeIntegerAdd(thyper, ! ConvertLongToLargeInteger(((char *) firstitem) - itembuf->datap)); ! thyper = ExtendedLargeIntegerDivide(thyper, 32, &junk); ! ! index = thyper.LowPart; ! osi_assert(thyper.HighPart == 0); ! ! nitems = cm_NameEntries(firstitem->name, NULL); ! cm_DirReleasePage(op, &itembuf, FALSE); ! ! cm_DirFreeBlobs(op, index, nitems); ! ! osi_Log0(afsd_logp, "cm_DirDeleteEntry returning success"); ! ! return 0; ! } ! ! /* Find a bunch of contiguous entries; at least nblobs in a row. ! ! Called with op->scp->mx */ ! static long ! cm_DirFindBlobs(cm_dirOp_t * op, int nblobs) ! { ! int i, j, k; ! int failed = 0; ! ! cm_dirHeader_t *dhp = NULL; ! cm_buf_t *dhpbuf = NULL; ! int dhpModified = FALSE; ! ! cm_pageHeader_t *pp = NULL; ! cm_buf_t *pagebuf = NULL; ! int pageModified = FALSE; ! ! int pgcount; ! ! long code; ! ! osi_Log2(afsd_logp, "cm_DirFindBlobs for op 0x%p, nblobs = %d", ! op, nblobs); ! ! code = cm_DirGetPage(op, 0, &dhpbuf, (void **) &dhp); ! if (code) ! return -1; ! ! for (i = 0; i < CM_DIR_BIGMAXPAGES; i++) { ! if (i >= CM_DIR_MAXPAGES || dhp->alloMap[i] >= nblobs) { ! /* if page could contain enough entries */ ! /* If there are CM_DIR_EPP free entries, then the page is ! not even allocated. */ ! if (i >= CM_DIR_MAXPAGES) { ! ! /* this pages exists past the end of the old-style dir */ ! pgcount = ntohs(dhp->header.pgcount); ! if (pgcount == 0) { ! pgcount = CM_DIR_MAXPAGES; ! dhp->header.pgcount = htons(pgcount); ! dhpModified = TRUE; ! } ! ! if (i > pgcount - 1) { ! /* this page is bigger than last allocated page */ ! cm_DirAddPage(op, i); ! dhp->header.pgcount = htons(i + 1); ! dhpModified = TRUE; ! } ! } else if (dhp->alloMap[i] == CM_DIR_EPP) { ! /* Add the page to the directory. */ ! cm_DirAddPage(op, i); ! dhp->alloMap[i] = CM_DIR_EPP - 1; ! dhp->header.pgcount = htons(i + 1); ! dhpModified = TRUE; ! } ! ! code = cm_DirGetPage(op, i, &pagebuf, &pp); ! if (code) { ! cm_DirReleasePage(op, &dhpbuf, dhpModified); ! break; ! } ! ! for (j = 0; j <= CM_DIR_EPP - nblobs; j++) { ! failed = 0; ! for (k = 0; k < nblobs; k++) ! if ((pp->freeBitmap[(j + k) >> 3] >> ((j + k) & 7)) & 1) { ! failed = 1; ! break; ! } ! if (!failed) ! break; ! failed = 1; ! } ! ! if (!failed) { ! /* Here we have the first index in j. We update the allocation maps ! * and free up any resources we've got allocated. */ ! if (i < CM_DIR_MAXPAGES) { ! dhp->alloMap[i] -= nblobs; ! dhpModified = TRUE; ! } ! ! cm_DirReleasePage(op, &dhpbuf, dhpModified); ! ! for (k = 0; k < nblobs; k++) ! pp->freeBitmap[(j + k) >> 3] |= 1 << ((j + k) & 7); ! ! cm_DirReleasePage(op, &pagebuf, TRUE); ! ! osi_Log0(afsd_logp, "cm_DirFindBlobs returning success"); ! ! return j + i * CM_DIR_EPP; ! } ! cm_DirReleasePage(op, &pagebuf, pageModified); ! } ! } ! ! /* If we make it here, the directory is full. */ ! osi_Log0(afsd_logp, "cm_DirFindBlobs directory is full"); ! cm_DirReleasePage(op, &dhpbuf, dhpModified); ! return -1; ! } ! ! /* Add a page to a directory. ! ! Called with op->scp->mx ! */ ! static long ! cm_DirAddPage(cm_dirOp_t * op, int pageno) ! { ! int i; ! cm_pageHeader_t *pp = NULL; ! cm_buf_t *pagebuf = NULL; ! long code = 0; ! ! osi_Log2(afsd_logp, "cm_DirAddPage for op 0x%p, pageno=%d", op, pageno); ! ! code = cm_DirGetPage(op, pageno, &pagebuf, (void **) &pp); ! if (code != 0) ! return code; ! ! pp->tag = htons(1234); ! if (pageno > 0) ! pp->pgcount = 0; ! pp->freeCount = CM_DIR_EPP - 1; /* The first dude is already allocated */ ! pp->freeBitmap[0] = 0x01; ! for (i = 1; i < CM_DIR_EPP / 8; i++) /* It's a constant */ ! pp->freeBitmap[i] = 0; ! ! cm_DirReleasePage(op, &pagebuf, TRUE); ! ! osi_Log0(afsd_logp, "cm_DirAddPage returning success"); ! ! return code; ! } ! ! /* Free a whole bunch of directory entries. ! ! Called with op->scp->mx ! */ ! static long ! cm_DirFreeBlobs(cm_dirOp_t * op, int firstblob, int nblobs) ! { ! int i; ! int page; ! ! cm_dirHeader_t *dhp = NULL; ! cm_buf_t *dhpbuf = NULL; ! int dhpmodified = FALSE; ! ! cm_pageHeader_t *pp = NULL; ! cm_buf_t *pagebuf = NULL; ! long code = 0; ! ! osi_Log3(afsd_logp, "cm_DirFreeBlobs for op 0x%p, firstblob=%d, nblobs=%d", ! op, firstblob, nblobs); ! ! page = firstblob / CM_DIR_EPP; ! firstblob -= CM_DIR_EPP * page; /* convert to page-relative entry */ ! ! code = cm_DirGetPage(op, 0, &dhpbuf, &dhp); ! if (code) ! return code; ! ! if (page < CM_DIR_MAXPAGES) { ! dhp->alloMap[page] += nblobs; ! dhpmodified = TRUE; ! } ! ! cm_DirReleasePage(op, &dhpbuf, dhpmodified); ! ! code = cm_DirGetPage(op, page, &pagebuf, &pp); ! if (code == 0) { ! for (i = 0; i < nblobs; i++) ! pp->freeBitmap[(firstblob + i) >> 3] &= ! ~(1 << ((firstblob + i) & 7)); ! cm_DirReleasePage(op, &pagebuf, TRUE); ! } ! ! osi_Log1(afsd_logp, "cm_DirFreeBlobs returning code 0x%x", code); ! ! return code; ! } ! ! /* ! * Format an empty directory properly. Note that the first 13 entries in a ! * directory header page are allocated, 1 to the page header, 4 to the ! * allocation map and 8 to the hash table. ! * ! * Called with op->scp->mx ! */ ! int ! cm_DirMakeDir(cm_dirOp_t * op, cm_fid_t * me, cm_fid_t * parent) ! { ! int i; ! cm_dirHeader_t *dhp = NULL; ! cm_buf_t *dhpbuf = NULL; ! ! long code; ! ! osi_Log3(afsd_logp, "cm_DirMakeDir for op 0x%p, directory fid[%d, %d]", ! op, me->vnode, me->unique); ! osi_Log2(afsd_logp, " parent[%d, %d]", ! parent->vnode, parent->unique); ! ! code = cm_DirGetPage(op, 0, &dhpbuf, &dhp); ! if (code) ! return 1; ! ! dhp->header.pgcount = htons(1); ! dhp->header.tag = htons(1234); ! dhp->header.freeCount = (CM_DIR_EPP - CM_DIR_DHE - 1); ! dhp->header.freeBitmap[0] = 0xff; ! dhp->header.freeBitmap[1] = 0x1f; ! for (i = 2; i < CM_DIR_EPP / 8; i++) ! dhp->header.freeBitmap[i] = 0; ! dhp->alloMap[0] = (CM_DIR_EPP - CM_DIR_DHE - 1); ! for (i = 1; i < CM_DIR_MAXPAGES; i++) ! dhp->alloMap[i] = CM_DIR_EPP; ! for (i = 0; i < CM_DIR_NHASHENT; i++) ! dhp->hashTable[i] = 0; ! ! cm_DirReleasePage(op, &dhpbuf, TRUE); ! ! cm_DirCreateEntry(op, ".", me); ! cm_DirCreateEntry(op, "..", parent); /* Virtue is its own .. */ ! ! osi_Log0(afsd_logp, "cm_DirMakeDir returning success"); ! ! return 0; ! } ! ! /* Look up a file name in directory. ! ! On entry: ! op->scp->mx is locked ! ! On exit: ! op->scp->mx is locked ! ! None of the directory buffers for op->scp should be locked by the ! calling thread. ! */ ! int ! cm_DirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid) ! { ! cm_dirEntry_t *firstitem = NULL; ! cm_buf_t *itembuf = NULL; ! unsigned short *previtem = NULL; ! cm_buf_t *pibuf = NULL; ! ! long code; ! ! osi_Log2(afsd_logp, "cm_DirLookup for op 0x%p, entry[%s]", ! op, osi_LogSaveString(afsd_logp, entry)); ! ! code = cm_DirFindItem(op, entry, ! &itembuf, &firstitem, ! &pibuf, &previtem); ! if (code != 0) { ! return ENOENT; ! } ! ! cm_DirReleasePage(op, &pibuf, FALSE); ! ! cfid->cell = op->scp->fid.cell; ! cfid->volume = op->scp->fid.volume; ! cfid->vnode = ntohl(firstitem->fid.vnode); ! cfid->unique = ntohl(firstitem->fid.unique); ! ! cm_DirReleasePage(op, &itembuf, FALSE); ! ! osi_Log2(afsd_logp, "cm_DirLookup returning fid[%d,%d]", ! cfid->vnode, cfid->unique); ! ! return 0; ! } ! ! /* Look up a file name in directory. ! ! On entry: ! op->scp->mx is locked ! ! On exit: ! op->scp->mx is locked ! ! None of the directory buffers for op->scp should be locked by the ! calling thread. ! */ ! int ! cm_DirLookupOffset(cm_dirOp_t * op, char *entry, cm_fid_t *cfid, osi_hyper_t *offsetp) ! { ! cm_dirEntry_t *firstitem = NULL; ! cm_buf_t *itembuf = NULL; ! unsigned short *previtem = NULL; ! cm_buf_t *pibuf = NULL; ! ! long code; ! ! osi_Log2(afsd_logp, "cm_DirLookupOffset for op 0x%p, entry[%s]", ! op, osi_LogSaveString(afsd_logp, entry)); ! ! code = cm_DirFindItem(op, entry, ! &itembuf, &firstitem, ! &pibuf, &previtem); ! if (code != 0) ! return ENOENT; ! ! cm_DirReleasePage(op, &pibuf, FALSE); ! ! cfid->cell = op->scp->fid.cell; ! cfid->volume = op->scp->fid.volume; ! cfid->vnode = ntohl(firstitem->fid.vnode); ! cfid->unique = ntohl(firstitem->fid.unique); ! if (offsetp) { ! osi_hyper_t thyper; ! ! thyper = itembuf->offset; ! thyper = LargeIntegerAdd(thyper, ! ConvertLongToLargeInteger(((char *) firstitem) - itembuf->datap)); ! ! *offsetp = thyper; ! } ! ! cm_DirReleasePage(op, &itembuf, FALSE); ! ! osi_Log2(afsd_logp, "cm_DirLookupOffset returning fid[%d,%d]", ! cfid->vnode, cfid->unique); ! if (offsetp) { ! osi_Log2(afsd_logp, " offset [%x:%x]", ! offsetp->HighPart, offsetp->LowPart); ! } ! ! return 0; ! } ! ! /* Apply a function to every directory entry in a directory. ! ! On entry: ! op->scp->mx is locked ! ! On exit: ! op->scp->mx is locked ! ! None of the directory buffers for op->scp should be locked by the ! calling thread. ! ! The hook function cannot modify or lock any directory buffers. ! */ ! int ! cm_DirApply(cm_dirOp_t * op, int (*hookproc) (void *, char *, long, long), void *hook) ! { ! /* Enumerate the contents of a directory. */ ! int i; ! int num; ! ! cm_dirHeader_t *dhp = NULL; ! cm_buf_t *dhpbuf = NULL; ! ! cm_dirEntry_t *ep = NULL; ! cm_buf_t *epbuf = NULL; ! ! long code = 0; ! ! code = cm_DirGetPage(op, 0, &dhpbuf, &dhp); ! if (code != 0) ! return EIO; ! ! for (i = 0; i < CM_DIR_NHASHENT; i++) { ! /* For each hash chain, enumerate everyone on the list. */ ! num = ntohs(dhp->hashTable[i]); ! while (num != 0) { ! /* Walk down the hash table list. */ ! code = cm_DirGetBlob(op, num, &epbuf, &ep); ! if (code != 0) { ! cm_DirReleasePage(op, &dhpbuf, FALSE); ! return code; ! } ! ! num = ntohs(ep->next); ! (*hookproc) (hook, ep->name, ntohl(ep->fid.vnode), ! ntohl(ep->fid.unique)); ! ! cm_DirReleasePage(op, &epbuf, FALSE); ! } ! } ! cm_DirReleasePage(op, &dhpbuf, FALSE); ! ! return 0; ! } ! ! /* Check if a directory is empty ! ! On entry: ! op->scp->mx is locked ! ! On exit: ! op->scp->mx is locked ! ! None of the directory buffers for op->scp should be locked by the ! calling thread. ! */ ! int ! cm_DirIsEmpty(cm_dirOp_t * op) ! { ! /* Enumerate the contents of a directory. */ ! int i; ! int num; ! ! cm_dirHeader_t *dhp = NULL; ! cm_buf_t *dhpbuf = NULL; ! ! cm_dirEntry_t *ep = NULL; ! cm_buf_t *epbuf = NULL; ! ! long code = 0; ! ! code = cm_DirGetPage(op, 0, &dhpbuf, &dhp); ! if (code != 0) ! return 0; ! ! for (i = 0; i < CM_DIR_NHASHENT; i++) { ! /* For each hash chain, enumerate everyone on the list. */ ! num = ntohs(dhp->hashTable[i]); ! ! while (num != 0) { ! /* Walk down the hash table list. */ ! code = cm_DirGetBlob(op, num, &epbuf, &ep); ! if (code != 0) ! break; ! ! if (strcmp(ep->name, "..") && strcmp(ep->name, ".")) { ! cm_DirReleasePage(op, &epbuf, FALSE); ! cm_DirReleasePage(op, &dhpbuf, FALSE); ! return 1; ! } ! num = ntohs(ep->next); ! cm_DirReleasePage(op, &epbuf, FALSE); ! } ! } ! cm_DirReleasePage(op, &dhpbuf, FALSE); ! return 0; ! } ! ! /* Return a pointer to an entry, given its number. ! ! On entry: ! scp->mx locked ! if *bufferpp != NULL, then *bufferpp->mx is locked ! ! During: ! scp->mx may be unlocked ! *bufferpp may be released ! ! On exit: ! scp->mx locked ! if *bufferpp != NULL, then *bufferpp->mx is locked ! ! *bufferpp should be released via cm_DirReleasePage() or any other ! *call that releases a directory buffer. ! */ ! static long ! cm_DirGetBlob(cm_dirOp_t * op, ! unsigned int blobno, cm_buf_t ** bufferpp, cm_dirEntry_t ** blobpp) ! { ! unsigned char * ep; ! long code = 0; ! ! osi_Log2(afsd_logp, "cm_DirGetBlob for op 0x%p, blobno=%d", ! op, blobno); ! ! code = cm_DirGetPage(op, blobno >> CM_DIR_LEPP, ! bufferpp, (void **) &ep); ! if (code != 0) ! return code; ! ! *blobpp = (cm_dirEntry_t *) (ep + 32 * (blobno & (CM_DIR_EPP - 1))); ! ! return code; } + + int + cm_DirHash(char *string) + { + /* Hash a string to a number between 0 and NHASHENT. */ + register unsigned char tc; + register int hval; + register int tval; + hval = 0; + while ((tc = (*string++))) { + hval *= 173; + hval += tc; + } + tval = hval & (CM_DIR_NHASHENT - 1); + if (tval == 0) + return tval; + else if (hval < 0) + tval = CM_DIR_NHASHENT - tval; + return tval; + } + + /* Find a directory entry, given its name. This entry returns a + * pointer to a locked buffer, and a pointer to a locked buffer (in + * previtem) referencing the found item (to aid the delete code). If + * no entry is found, however, no items are left locked, and a null + * pointer is returned instead. + * + * On entry: + * scp->mx locked + * + * On exit: + * scp->mx locked + */ + static long + cm_DirFindItem(cm_dirOp_t * op, + char *ename, + cm_buf_t ** itembufpp, cm_dirEntry_t ** itempp, + cm_buf_t ** prevbufpp, unsigned short **previtempp) + { + int i; + cm_dirHeader_t *dhp = NULL; + unsigned short *lp = NULL; + cm_dirEntry_t *tp = NULL; + cm_buf_t *hashbufp = NULL; + cm_buf_t *itembufp = NULL; + long code = 0; + + osi_Log2(afsd_logp, "cm_DirFindItem for op 0x%p, entry[%s]", + op, osi_LogSaveString(afsd_logp, ename)); + + i = cm_DirHash(ename); + + if (op->scp->fileType != CM_SCACHETYPE_DIRECTORY) { + osi_Log0(afsd_logp, "cm_DirFindItem: The scp is not a directory"); + return CM_ERROR_INVAL; + } + + code = cm_DirGetPage(op, 0, &hashbufp, (void **) &dhp); + if (code != 0) { + return code; + } + + if (dhp->hashTable[i] == 0) { + /* no such entry */ + osi_Log1(afsd_logp, "cm_DirFindItem: Hash bucket %d is empty", i); + cm_DirReleasePage(op, &hashbufp, FALSE); + return ENOENT; + } + + code = cm_DirGetBlob(op, + (u_short) ntohs(dhp->hashTable[i]), + &itembufp, &tp); + if (code != 0) { + cm_DirReleasePage(op, &hashbufp, FALSE); + return code; + } + + lp = &(dhp->hashTable[i]); + + /* loop invariant: + + lp : pointer to blob number of entry we are looking at + hashbufp : buffer containing lp + tp : pointer to entry we are looking at + itembufp : buffer containing tp + */ + while (1) { + /* Look at each hash conflict entry. */ + if (!strcmp(ename, tp->name)) { + osi_Log0(afsd_logp, "cm_DirFindItem: returning success"); + /* Found our entry. */ + *previtempp = lp; + *prevbufpp = hashbufp; + *itempp = tp; + *itembufpp = itembufp; + return 0; + } + + lp = &(tp->next); + cm_DirReleasePage(op, &hashbufp, FALSE); + hashbufp = itembufp; + + itembufp = NULL; + tp = NULL; + + if (*lp == 0) { + /* The end of the line */ + osi_Log0(afsd_logp, "cm_DirFindItem: returning ENOENT"); + cm_DirReleasePage(op, &hashbufp, FALSE); + return ENOENT; + } + + code = cm_DirGetBlob(op, + (u_short) ntohs(*lp), + &itembufp, &tp); + + if (code != 0) { + cm_DirReleasePage(op, &hashbufp, FALSE); + return code; + } + } + } + + /* Begin a sequence of directory operations. scp->mx should be + locked. + */ + long + cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp, + cm_dirOp_t * op) + { + long code; + int i; + + osi_Log3(afsd_logp, "Beginning dirOp[0x%p] for scp[0x%p], userp[0x%p]", + op, scp, userp); + + memset(op, 0, sizeof(*op)); + + cm_HoldSCache(scp); + op->scp = scp; + cm_HoldUser(userp); + op->userp = userp; + cm_InitReq(&op->req); + + op->dirtyBufCount = 0; + op->nBuffers = 0; + + for (i=0; i < CM_DIROP_MAXBUFFERS; i++) { + op->buffers[i].flags = 0; + } + + code = cm_DirCheckStatus(op); + + if (code == 0) { + op->length = scp->length; + op->newLength = op->length; + op->dataVersion = scp->dataVersion; + op->newDataVersion = op->dataVersion; + } else { + cm_EndDirOp(op); + } + + return code; + } + + /* Check if it is safe for us to perform local directory updates. + Called with scp->mx held. */ + int + cm_CheckDirOpForSingleChange(cm_dirOp_t * op) + { + long code; + + if (op->scp == NULL) + return 0; + + code = cm_DirCheckStatus(op); + + if (code == 0 && + op->dataVersion == op->scp->dataVersion - 1) { + /* only one set of changes happened between cm_BeginDirOp() + and this function. It is safe for us to perform local + changes. */ + op->newDataVersion = op->scp->dataVersion; + op->newLength = op->scp->serverLength; + + osi_Log0(afsd_logp, "cm_CheckDirOpForSingleChange succeeded"); + + return 1; + } + + osi_Log3(afsd_logp, + "cm_CheckDirOpForSingleChange failed. code=0x%x, old dv=%d, new dv=%d", + code, op->dataVersion, op->scp->dataVersion); + return 0; + } + + /* End a sequence of directory operations. Called with op->scp->mx + locked.*/ + long + cm_EndDirOp(cm_dirOp_t * op) + { + long code = 0; + + if (op->scp == NULL) + return 0; + + osi_Log2(afsd_logp, "Ending dirOp 0x%p with %d dirty buffer releases", + op, op->dirtyBufCount); + + if (op->dirtyBufCount > 0) { + /* we made changes. We should go through the list of buffers + and update the dataVersion for each. */ + + lock_ReleaseMutex(&op->scp->mx); + code = buf_ForceDataVersion(op->scp, op->dataVersion, op->newDataVersion); + lock_ObtainMutex(&op->scp->mx); + } + + if (op->scp) + cm_ReleaseSCache(op->scp); + op->scp = NULL; + + if (op->userp) + cm_ReleaseUser(op->userp); + op->userp = 0; + + osi_assertx(op->nBuffers == 0, "Buffer leak after dirOp termination"); + + return code; + } + + /* NOTE: Called without scp->mx and without bufferp->mx */ + static long + cm_DirOpAddBuffer(cm_dirOp_t * op, cm_buf_t * bufferp) + { + int i; + long code = 0; + + osi_Log2(afsd_logp, "cm_DirOpAddBuffer for op 0x%p, buffer %p", op, bufferp); + + if (bufferp == NULL) + return -1; + + for (i=0; i < CM_DIROP_MAXBUFFERS; i++) { + if ((op->buffers[i].flags & CM_DIROPBUFF_INUSE) && + op->buffers[i].bufferp == bufferp) { + break; + } + } + + if (i < CM_DIROP_MAXBUFFERS) { + /* we already have this buffer on our list */ + + op->buffers[i].refcount++; + osi_Log0(afsd_logp, + "cm_DirOpAddBuffer: the buffer is already listed for the dirOp"); + return 0; + } else { + /* we have to add a new buffer */ + osi_assertx(op->nBuffers < CM_DIROP_MAXBUFFERS - 1, + "DirOp has exceeded CM_DIROP_MAXBUFFERS buffers"); + + for (i=0; i < CM_DIROP_MAXBUFFERS; i++) { + if (!(op->buffers[i].flags & CM_DIROPBUFF_INUSE)) + break; + } + + osi_assert(i < CM_DIROP_MAXBUFFERS); + + lock_ObtainMutex(&bufferp->mx); + lock_ObtainMutex(&op->scp->mx); + + /* Make sure we are synchronized. */ + code = cm_SyncOp(op->scp, bufferp, op->userp, &op->req, PRSFS_LOOKUP, + CM_SCACHESYNC_NEEDCALLBACK | + CM_SCACHESYNC_WRITE | + CM_SCACHESYNC_BUFLOCKED); + + if (code == 0 && + bufferp->dataVersion != op->dataVersion) { + + osi_Log2(afsd_logp, "cm_DirOpAddBuffer: buffer version mismatch. buf ver = %d. want %d", bufferp->dataVersion, op->dataVersion); + + cm_SyncOpDone(op->scp, bufferp, + CM_SCACHESYNC_NEEDCALLBACK | + CM_SCACHESYNC_WRITE | + CM_SCACHESYNC_BUFLOCKED); + + code = CM_ERROR_INVAL; + } + + lock_ReleaseMutex(&op->scp->mx); + lock_ReleaseMutex(&bufferp->mx); + + if (code) { + osi_Log1(afsd_logp, "cm_DirOpAddBuffer: failed to sync buffer. code=0x%x", + code); + return code; + } + + buf_Hold(bufferp); + op->buffers[i].bufferp = bufferp; + op->buffers[i].refcount = 1; /* start with one ref */ + op->buffers[i].flags = CM_DIROPBUFF_INUSE; + + op->nBuffers++; + + osi_Log0(afsd_logp, "cm_DirOpAddBuffer: returning success"); + + return 0; + } + } + + /* Note: Called without op->scp->mx */ + static int + cm_DirOpFindBuffer(cm_dirOp_t * op, osi_hyper_t offset, cm_buf_t ** bufferpp) + { + int i; + + for (i=0; i < CM_DIROP_MAXBUFFERS; i++) { + if ((op->buffers[i].flags & CM_DIROPBUFF_INUSE) && + LargeIntegerEqualTo(op->buffers[i].bufferp->offset, offset)) + break; + } + + if (i < CM_DIROP_MAXBUFFERS) { + /* found it */ + op->buffers[i].refcount++; + buf_Hold(op->buffers[i].bufferp); + *bufferpp = op->buffers[i].bufferp; + + osi_Log2(afsd_logp, "cm_DirOpFindBuffer: found buffer for offset [%x:%x]", + offset.HighPart, offset.LowPart); + return 1; + } + + osi_Log2(afsd_logp, "cm_DirOpFindBuffer: buffer not found for offset [%x:%x]", + offset.HighPart, offset.LowPart); + return 0; + } + + + /* NOTE: called with scp->mx NOT held */ + static int + cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * bufferp, int flags) + { + int i; + + osi_Log3(afsd_logp, "cm_DirOpDelBuffer for op 0x%p, buffer 0x%p, flags=%d", + op, bufferp, flags); + + for (i=0; i < CM_DIROP_MAXBUFFERS; i++) { + if ((op->buffers[i].flags & CM_DIROPBUFF_INUSE) && + op->buffers[i].bufferp == bufferp) + break; + } + + if (i < CM_DIROP_MAXBUFFERS) { + + if (flags & DIROP_MODIFIED) + op->dirtyBufCount++; + + osi_assert(op->buffers[i].refcount > 0); + op->buffers[i].refcount --; + + if (op->buffers[i].refcount == 0) { + /* this was the last reference we had */ + + osi_Log0(afsd_logp, "cm_DirOpDelBuffer: releasing buffer"); + + /* if this buffer was modified, then we update the data + version of the buffer with the data version of the + scp. */ + if (!(flags & DIROP_SCPLOCKED)) { + lock_ObtainMutex(&op->scp->mx); + } + + /* first make sure that the buffer is idle. It should + have been idle all along. */ + osi_assertx((bufferp->cmFlags & (CM_BUF_CMFETCHING | + CM_BUF_CMSTORING)) == 0, + "Buffer is not idle while performing dirOp"); + + cm_SyncOpDone(op->scp, bufferp, + CM_SCACHESYNC_NEEDCALLBACK | + CM_SCACHESYNC_WRITE); + + #ifdef DEBUG + osi_assert(bufferp->dataVersion == op->dataVersion); + #endif + + lock_ReleaseMutex(&op->scp->mx); + + lock_ObtainMutex(&bufferp->mx); + + if (flags & DIROP_SCPLOCKED) { + lock_ObtainMutex(&op->scp->mx); + } + + if (flags & DIROP_MODIFIED) { + /* We don't update the dataversion here. Instead we + wait until the dirOp is completed and then flip the + dataversion on all the buffers in one go. + Otherwise we won't know if the dataversion is + current because it was fetched from the server or + because we touched it during the dirOp. */ + + if (bufferp->userp != op->userp) { + if (bufferp->userp != NULL) + cm_ReleaseUser(bufferp->userp); + cm_HoldUser(op->userp); + bufferp->userp = op->userp; + } + } + + lock_ReleaseMutex(&bufferp->mx); + + op->buffers[i].bufferp = NULL; + buf_Release(bufferp); + op->buffers[i].flags = 0; + + op->nBuffers--; + + return 1; + } else { + /* we have other references to this buffer. so we have to + let it be */ + return 0; + } + + } else { + osi_Log0(afsd_logp, "cm_DirOpDelBuffer: buffer not found"); + osi_assertx(FALSE, "Attempt to delete a non-existent buffer from a dirOp"); + return -1; + } + } + + /* Check if we have current status and a callback for the given scp. + This should be called before cm_DirGetPage() is called per scp. + + On entry: + scp->mx locked + + On exit: + scp->mx locked + + During: + scp->mx may be released + */ + static long + cm_DirCheckStatus(cm_dirOp_t * op) + { + long code; + + code = cm_SyncOp(op->scp, NULL, op->userp, &op->req, PRSFS_LOOKUP, + CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + + osi_Log2(afsd_logp, "cm_DirCheckStatus for op 0x%p returning code 0x%x", + op, code); + + return code; + } + + /* Release a directory buffer that was obtained via a call to + cm_DirGetPage() or any other function that returns a locked, held, + directory page buffer. + + Called with scp->mx held + */ + static long + cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified) + { + long code = 0; + + if (!*bufferpp) + return EINVAL; + + cm_DirOpDelBuffer(op, *bufferpp, + ((modified ? DIROP_MODIFIED : 0) | DIROP_SCPLOCKED)); + buf_Release(*bufferpp); + *bufferpp = NULL; + + return code; + } + + /* + Returns the index'th directory page from scp. The userp and reqp + will be used to fetch the buffer from the fileserver if necessary. + If the call is successful, a locked and held cm_buf_t is returned + via buferpp and a pointer to the directory page is returned via + datapp. + + The returned buffer should be released via a call to + cm_DirReleasePage() or by passing it into a subsequent call to + cm_DirGetPage() for the *same* scp. + + If a *locked* buffer for the *same* scp is passed in via bufferpp + to the function, it will check if the requested directory page is + located in the specified buffer. If not, the buffer will be + released and a new buffer returned that contains the requested + page. + + Note: If a buffer is specified on entry via bufferpp, it is assumed + that the buffer is unmodified. If the buffer is modified, it + should be released via cm_DirReleasePage(). + + On entry: + scp->mx locked. + If *bufferpp is non-NULL, then *bufferpp->mx is locked. + + On exit: + scp->mxlocked + If *bufferpp is non-NULL, then *bufferpp->mx is locked. + + During: + scp->mx will be released + + */ + static long + cm_DirGetPage(cm_dirOp_t * op, + long index, cm_buf_t ** bufferpp, void ** datapp) + { + osi_hyper_t pageOffset; /* offset of the dir page from the + start of the directory */ + osi_hyper_t bufferOffset; /* offset of the buffer from the start + of the directory */ + osi_hyper_t thyper; + + cm_buf_t * bufferp = NULL; + + void * datap = NULL; + + long code = 0; + + osi_Log2(afsd_logp, "cm_DirGetPage for op 0x%p, index %d", op, index); + + pageOffset = ConvertLongToLargeInteger(index * CM_DIR_PAGESIZE); + bufferOffset.HighPart = pageOffset.HighPart; + bufferOffset.LowPart = pageOffset.LowPart & ~(cm_data.buf_blockSize - 1); + + bufferp = *bufferpp; + if (bufferp != NULL) { + osi_assert(cm_FidCmp(&bufferp->fid, &op->scp->fid) == 0); + + thyper = bufferp->offset; + } + + lock_ReleaseMutex(&op->scp->mx); + + if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) { + /* wrong buffer */ + + if (bufferp) { + buf_Release(bufferp); + cm_DirOpDelBuffer(op, bufferp, 0); + bufferp = NULL; + } + + /* first check if we are already working with the buffer */ + if (cm_DirOpFindBuffer(op, bufferOffset, &bufferp)) { + code = 0; + goto _has_buffer; + } + + lock_ObtainRead(&op->scp->bufCreateLock); + code = buf_Get(op->scp, &bufferOffset, &bufferp); + lock_ReleaseRead(&op->scp->bufCreateLock); + + if (code) { + osi_Log1(afsd_logp, " buf_Get returned code 0x%x", code); + bufferp = NULL; + goto _exit; + } + + osi_assert(bufferp != NULL); + + /* DirOpAddBuffer will obtain bufferp->mx if necessary */ + code = cm_DirOpAddBuffer(op, bufferp); + + if (code != 0) { + /* for some reason, the buffer was rejected. We can't use + this buffer, and since this is the only buffer we can + potentially use, there's no recourse.*/ + buf_Release(bufferp); + bufferp = NULL; + goto _exit; + } + + #if 0 + /* The code below is for making sure the buffer contains + current data. This is a bad idea, since the whole point of + doing directory updates locally is to avoid fetching all + the data from the server. */ + while (1) { + lock_ObtainMutex(&op->scp->mx); + code = cm_SyncOp(op->scp, bufferp, op->userp, &op->req, PRSFS_LOOKUP, + CM_SCACHESYNC_NEEDCALLBACK | + CM_SCACHESYNC_READ | + CM_SCACHESYNC_BUFLOCKED); + + if (code) { + lock_ReleaseMutex(&op->scp->mx); + break; + } + + cm_SyncOpDone(op->scp, bufferp, + CM_SCACHESYNC_NEEDCALLBACK | + CM_SCACHESYNC_READ | + CM_SCACHESYNC_BUFLOCKED); + + if (cm_HaveBuffer(op->scp, bufferp, 1)) { + lock_ReleaseMutex(&op->scp->mx); + break; + } + + lock_ReleaseMutex(&bufferp->mx); + code = cm_GetBuffer(op->scp, bufferp, NULL, op->userp, &op->req); + lock_ReleaseMutex(&op->scp->mx); + lock_ObtainMutex(&bufferp->mx); + + if (code) + break; + } + + if (code) { + cm_DirOpDelBuffer(op, bufferp, 0); + buf_Release(bufferp); + bufferp = NULL; + goto _exit; + } + #endif + } + + _has_buffer: + + /* now to figure out where the data is */ + thyper = LargeIntegerSubtract(pageOffset, bufferOffset); + + osi_assert(thyper.HighPart == 0); + osi_assert(cm_data.buf_blockSize > thyper.LowPart && + cm_data.buf_blockSize - thyper.LowPart >= CM_DIR_PAGESIZE); + + datap = (void *) (((char *)bufferp->datap) + thyper.LowPart); + + if (datapp) + *datapp = datap; + + /* also, if we are writing past EOF, we should make a note of the + new length */ + thyper = LargeIntegerAdd(pageOffset, + ConvertLongToLargeInteger(CM_DIR_PAGESIZE)); + if (LargeIntegerLessThan(op->newLength, thyper)) { + op->newLength = thyper; + } + + _exit: + + *bufferpp = bufferp; + if (op->scp) + lock_ObtainMutex(&op->scp->mx); + + osi_Log1(afsd_logp, "cm_DirGetPage returning code 0x%x", code); + + return code; + } + + + void + cm_DirEntryListAdd(char * namep, cm_dirEntryList_t ** list) + { + size_t len; + cm_dirEntryList_t * entry; + + len = strlen(namep); + len += sizeof(cm_dirEntryList_t); + + entry = malloc(len); + if (entry) { + entry->nextp = *list; + strcpy(entry->name, namep); + *list = entry; + } + } + + void + cm_DirEntryListFree(cm_dirEntryList_t ** list) + { + cm_dirEntryList_t * entry; + cm_dirEntryList_t * next; + + for (entry = *list; entry; entry = next) { + next = entry->nextp; + free(entry); + } + + *list = NULL; + } + Index: openafs/src/WINNT/afsd/cm_dir.h diff -c openafs/src/WINNT/afsd/cm_dir.h:1.4.4.1 openafs/src/WINNT/afsd/cm_dir.h:1.4.4.2 *** openafs/src/WINNT/afsd/cm_dir.h:1.4.4.1 Mon Feb 19 22:14:45 2007 --- openafs/src/WINNT/afsd/cm_dir.h Thu Aug 2 16:53:52 2007 *************** *** 31,36 **** --- 31,39 ---- * header alone. */ + #define CM_DIR_FFIRST 1 + #define CM_DIR_FNEXT 2 + typedef struct cm_dirFid { /* A file identifier. */ afs_int32 vnode; /* file's vnode slot */ *************** *** 56,63 **** unsigned short hashTable[CM_DIR_NHASHENT]; } cm_dirHeader_t; ! /* this represents a directory entry. We use strlen to find out how many bytes are ! * really in the dir entry; it is always a multiple of 32. */ typedef struct cm_dirEntry { /* A directory entry */ --- 59,67 ---- unsigned short hashTable[CM_DIR_NHASHENT]; } cm_dirHeader_t; ! /* this represents a directory entry. We use strlen to find out how ! * many bytes are really in the dir entry; it is always a multiple of ! * 32. */ typedef struct cm_dirEntry { /* A directory entry */ *************** *** 87,92 **** } cm_dirPage1_t; #endif /* UNUSED */ ! extern long cm_NameEntries(char *namep, long *lenp); #endif /* __CM_DIR_ENV__ */ --- 91,178 ---- } cm_dirPage1_t; #endif /* UNUSED */ ! #define CM_DIROP_MAXBUFFERS 8 ! ! typedef struct cm_dirOpBuffer { ! int flags; ! cm_buf_t * bufferp; ! int refcount; ! } cm_dirOpBuffer_t; ! ! #define CM_DIROPBUFF_INUSE 0x1 ! ! /* Used for managing transactional directory operations. Each ! instance should only be used by one thread. */ ! typedef struct cm_dirOp { ! cm_scache_t * scp; ! cm_user_t * userp; ! cm_req_t req; ! ! osi_hyper_t length; /* scp->length at the time ! cm_BeginDirOp() was called.*/ ! osi_hyper_t newLength; /* adjusted scp->length */ ! afs_uint32 dataVersion; /* scp->dataVersion when ! cm_BeginDirOp() was called.*/ ! afs_uint32 newDataVersion; /* scp->dataVersion when ! cm_CheckDirOpForSingleChange() ! was called. */ ! ! afs_uint32 dirtyBufCount; ! ! int nBuffers; /* number of buffers below */ ! cm_dirOpBuffer_t buffers[CM_DIROP_MAXBUFFERS]; ! } cm_dirOp_t; ! ! extern long ! cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp, ! cm_dirOp_t * op); ! ! extern int ! cm_CheckDirOpForSingleChange(cm_dirOp_t * op); ! ! extern long ! cm_EndDirOp(cm_dirOp_t * op); ! ! extern long ! cm_NameEntries(char *namep, long *lenp); ! ! extern long ! cm_DirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid); ! ! extern int ! cm_DirLength(cm_dirOp_t * op); ! ! extern int ! cm_DirDeleteEntry(cm_dirOp_t * op, char *entry); ! ! extern int ! cm_DirMakeDir(cm_dirOp_t * op, cm_fid_t * me, cm_fid_t * parent); ! ! extern int ! cm_DirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid); ! ! extern int ! cm_DirLookupOffset(cm_dirOp_t * op, char *entry, cm_fid_t *cfid, osi_hyper_t *offsetp); ! ! extern int ! cm_DirApply(cm_dirOp_t * op, int (*hookproc) (void *, char *, long, long), void *hook); ! ! extern int ! cm_DirIsEmpty(cm_dirOp_t * op); ! ! extern int ! cm_DirHash(char *string); ! ! /* Directory entry lists */ ! typedef struct cm_dirEntryList { ! struct cm_dirEntryList * nextp; ! char name[1]; ! } cm_dirEntryList_t; ! ! extern void ! cm_DirEntryListAdd(char * namep, cm_dirEntryList_t ** list); ! ! extern void ! cm_DirEntryListFree(cm_dirEntryList_t ** list); #endif /* __CM_DIR_ENV__ */ Index: openafs/src/WINNT/afsd/cm_ioctl.c diff -c openafs/src/WINNT/afsd/cm_ioctl.c:1.73.2.18 openafs/src/WINNT/afsd/cm_ioctl.c:1.73.2.19 *** openafs/src/WINNT/afsd/cm_ioctl.c:1.73.2.18 Sat Jun 30 00:44:23 2007 --- openafs/src/WINNT/afsd/cm_ioctl.c Sun Jul 22 19:10:17 2007 *************** *** 1995,2001 **** if (r && !stricmp(r+1,ucellp->cellp->name)) *r = '\0'; ! code = ubik_Call(PR_NameToID, pruclient, 0, &lnames, &lids); if (lids.idlist_val) { *uid = *lids.idlist_val; free(lids.idlist_val); --- 1995,2001 ---- if (r && !stricmp(r+1,ucellp->cellp->name)) *r = '\0'; ! code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids); if (lids.idlist_val) { *uid = *lids.idlist_val; free(lids.idlist_val); Index: openafs/src/WINNT/afsd/cm_scache.c diff -c openafs/src/WINNT/afsd/cm_scache.c:1.35.2.39 openafs/src/WINNT/afsd/cm_scache.c:1.35.2.41 *** openafs/src/WINNT/afsd/cm_scache.c:1.35.2.39 Fri Jul 6 19:22:03 2007 --- openafs/src/WINNT/afsd/cm_scache.c Thu Aug 9 01:33:56 2007 *************** *** 107,112 **** --- 107,114 ---- lock_ObtainMutex(&bufp->mx); bufp->cmFlags &= ~CM_BUF_CMSTORING; bufp->flags &= ~CM_BUF_DIRTY; + bufp->dirty_offset = 0; + bufp->dirty_length = 0; bufp->flags |= CM_BUF_ERROR; bufp->error = VNOVNODE; bufp->dataVersion = -1; /* bad */ *************** *** 127,132 **** --- 129,136 ---- lock_ObtainMutex(&bufp->mx); bufp->cmFlags &= ~CM_BUF_CMFETCHING; bufp->flags &= ~CM_BUF_DIRTY; + bufp->dirty_offset = 0; + bufp->dirty_length = 0; bufp->flags |= CM_BUF_ERROR; bufp->error = VNOVNODE; bufp->dataVersion = -1; /* bad */ *************** *** 966,973 **** osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESTORING|GETCALLBACK want FETCHDATA", scp); goto sleep; } ! if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING))) { ! osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMFETCHING|BUF_CMSTORING want FETCHDATA", scp, bufp); goto sleep; } } --- 970,977 ---- osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESTORING|GETCALLBACK want FETCHDATA", scp); goto sleep; } ! if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING | CM_BUF_CMWRITING))) { ! osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMFETCHING|BUF_CMSTORING|BUF_CMWRITING want FETCHDATA", scp, bufp); goto sleep; } } *************** *** 978,985 **** osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESTORING|GETCALLBACK want STOREDATA", scp); goto sleep; } ! if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING))) { ! osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMFETCHING|BUF_CMSTORING want STOREDATA", scp, bufp); goto sleep; } } --- 982,989 ---- osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESTORING|GETCALLBACK want STOREDATA", scp); goto sleep; } ! if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING | CM_BUF_CMWRITING))) { ! osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMFETCHING|BUF_CMSTORING|BUF_CMWRITING want STOREDATA", scp, bufp); goto sleep; } } *************** *** 1045,1050 **** --- 1049,1058 ---- osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMFETCHING want READ", scp, bufp); goto sleep; } + if (bufp && (bufp->cmFlags & CM_BUF_CMWRITING)) { + osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMWRITING want READ", scp, bufp); + goto sleep; + } } if (flags & CM_SCACHESYNC_WRITE) { /* don't write unless the status is stable and the chunk *************** *** 1055,1062 **** osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESTORING want WRITE", scp); goto sleep; } ! if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING))) { ! osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMFETCHING|BUF_CMSTORING want WRITE", scp, bufp); goto sleep; } } --- 1063,1077 ---- osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESTORING want WRITE", scp); goto sleep; } ! if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | ! CM_BUF_CMSTORING | ! CM_BUF_CMWRITING))) { ! osi_Log3(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is %s want WRITE", ! scp, bufp, ! ((bufp->cmFlags & CM_BUF_CMFETCHING) ? "CM_BUF_CMFETCHING": ! ((bufp->cmFlags & CM_BUF_CMSTORING) ? "CM_BUF_CMSTORING" : ! ((bufp->cmFlags & CM_BUF_CMWRITING) ? "CM_BUF_CMWRITING" : ! "UNKNOWN!!!")))); goto sleep; } } *************** *** 1217,1222 **** --- 1232,1244 ---- osi_QAdd((osi_queue_t **) &scp->bufWritesp, &qdp->q); } + if (flags & CM_SCACHESYNC_WRITE) { + /* mark the buffer as being written to. */ + if (bufp) { + bufp->cmFlags |= CM_BUF_CMWRITING; + } + } + return 0; } *************** *** 1297,1302 **** --- 1319,1332 ---- } } + if (flags & CM_SCACHESYNC_WRITE) { + if (bufp) { + osi_assert(bufp->cmFlags & CM_BUF_CMWRITING); + + bufp->cmFlags &= ~CM_BUF_CMWRITING; + } + } + /* and wakeup anyone who is waiting */ if (scp->flags & CM_SCACHEFLAG_WAITING) { osi_Log1(afsd_logp, "CM SyncOpDone Waking scp 0x%p", scp); Index: openafs/src/WINNT/afsd/cm_server.c diff -c openafs/src/WINNT/afsd/cm_server.c:1.25.2.11 openafs/src/WINNT/afsd/cm_server.c:1.25.2.12 *** openafs/src/WINNT/afsd/cm_server.c:1.25.2.11 Sat Jul 7 09:38:33 2007 --- openafs/src/WINNT/afsd/cm_server.c Thu Aug 2 16:46:12 2007 *************** *** 110,115 **** --- 110,116 ---- if (code >= 0) { /* mark server as up */ tsp->flags &= ~CM_SERVERFLAG_DOWN; + tsp->downTime = 0; /* we currently handle 32-bits of capabilities */ if (caps.Capabilities_len > 0) { *************** *** 152,157 **** --- 153,159 ---- } else { /* mark server as down */ tsp->flags |= CM_SERVERFLAG_DOWN; + tsp->downTime = osi_Time(); if (code != VRESTARTING) cm_ForceNewConnections(tsp); Index: openafs/src/WINNT/afsd/cm_server.h diff -c openafs/src/WINNT/afsd/cm_server.h:1.13.2.8 openafs/src/WINNT/afsd/cm_server.h:1.13.2.9 *** openafs/src/WINNT/afsd/cm_server.h:1.13.2.8 Thu Jun 28 00:50:15 2007 --- openafs/src/WINNT/afsd/cm_server.h Thu Aug 2 16:46:12 2007 *************** *** 40,45 **** --- 40,46 ---- osi_mutex_t mx; unsigned short ipRank; /* server priority */ cm_server_vols_t * vols; /* by mx */ + time_t downTime; /* by mx */ } cm_server_t; enum repstate {srv_not_busy, srv_busy, srv_offline, srv_deleted}; Index: openafs/src/WINNT/afsd/cm_vnodeops.c diff -c openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.32 openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.34 *** openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.32 Wed Jun 13 18:28:25 2007 --- openafs/src/WINNT/afsd/cm_vnodeops.c Thu Aug 2 16:58:42 2007 *************** *** 604,618 **** { cm_lookupSearch_t* sp = parmp; #ifdef AFS_FREELANCE_CLIENT /* Freelance entries never end up in the DNLC because they * do not have an associated cm_server_t */ ! if ( !(cm_freelanceEnabled && sp->fid.cell==AFS_FAKE_ROOT_CELL_ID && ! sp->fid.volume==AFS_FAKE_ROOT_VOL_ID ) ) ! #endif /* AFS_FREELANCE_CLIENT */ ! { int casefold = sp->caseFold; sp->caseFold = 0; /* we have a strong preference for exact matches */ if ( *retscp = cm_dnlcLookup(scp, sp)) /* dnlc hit */ --- 604,621 ---- { cm_lookupSearch_t* sp = parmp; + if ( #ifdef AFS_FREELANCE_CLIENT /* Freelance entries never end up in the DNLC because they * do not have an associated cm_server_t */ ! !(cm_freelanceEnabled && sp->fid.cell==AFS_FAKE_ROOT_CELL_ID && ! sp->fid.volume==AFS_FAKE_ROOT_VOL_ID ) ! #else /* !AFS_FREELANCE_CLIENT */ ! TRUE ! #endif ! ) { int casefold = sp->caseFold; sp->caseFold = 0; /* we have a strong preference for exact matches */ if ( *retscp = cm_dnlcLookup(scp, sp)) /* dnlc hit */ *************** *** 622,627 **** --- 625,656 ---- return 0; } sp->caseFold = casefold; + + /* see if we can find it using the directory hash tables. + we can only do exact matches, since the hash is case + sensitive. */ + { + cm_dirOp_t dirop; + + code = ENOENT; + + code = cm_BeginDirOp(scp, userp, reqp, &dirop); + if (code == 0) { + code = cm_DirLookup(&dirop, sp->searchNamep, &sp->fid); + cm_EndDirOp(&dirop); + } + + if (code == 0) { + /* found it */ + sp->found = TRUE; + sp->ExactFound = TRUE; + lock_ReleaseMutex(&scp->mx); + + *retscp = NULL; /* force caller to call cm_GetSCache() */ + + return 0; + } + } } } *************** *** 1128,1133 **** --- 1157,1164 ---- cm_lookupSearch_t rock; int getroot; + memset(&rock, 0, sizeof(rock)); + if (dscp->fid.vnode == 1 && dscp->fid.unique == 1 && strcmp(namep, "..") == 0) { if (dscp->dotdotFid.volume == 0) *************** *** 1139,1145 **** goto haveFid; } ! memset(&rock, 0, sizeof(rock)); rock.fid.cell = dscp->fid.cell; rock.fid.volume = dscp->fid.volume; rock.searchNamep = namep; --- 1170,1199 ---- goto haveFid; } ! if (flags & CM_FLAG_NOMOUNTCHASE) { ! /* In this case, we should go and call cm_Dir* functions ! directly since the following cm_ApplyDir() function will ! not. */ ! ! cm_dirOp_t dirop; ! ! lock_ObtainMutex(&dscp->mx); ! ! code = cm_BeginDirOp(dscp, userp, reqp, &dirop); ! if (code == 0) { ! code = cm_DirLookup(&dirop, namep, &rock.fid); ! cm_EndDirOp(&dirop); ! } ! ! lock_ReleaseMutex(&dscp->mx); ! ! if (code == 0) { ! /* found it */ ! rock.found = TRUE; ! goto haveFid; ! } ! } ! rock.fid.cell = dscp->fid.cell; rock.fid.volume = dscp->fid.volume; rock.searchNamep = namep; *************** *** 1486,1491 **** --- 1540,1546 ---- AFSFetchStatus newDirStatus; AFSVolSync volSync; struct rx_connection * callp; + cm_dirOp_t dirop; #ifdef AFS_FREELANCE_CLIENT if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) { *************** *** 1497,1507 **** /* make sure we don't screw up the dir status during the merge */ lock_ObtainMutex(&dscp->mx); sflags = CM_SCACHESYNC_STOREDATA; code = cm_SyncOp(dscp, NULL, userp, reqp, 0, sflags); lock_ReleaseMutex(&dscp->mx); ! if (code) return code; /* make the RPC */ afsFid.Volume = dscp->fid.volume; --- 1552,1567 ---- /* make sure we don't screw up the dir status during the merge */ lock_ObtainMutex(&dscp->mx); + + code = cm_BeginDirOp(dscp, userp, reqp, &dirop); + sflags = CM_SCACHESYNC_STOREDATA; code = cm_SyncOp(dscp, NULL, userp, reqp, 0, sflags); lock_ReleaseMutex(&dscp->mx); ! if (code) { ! cm_EndDirOp(&dirop); return code; + } /* make the RPC */ afsFid.Volume = dscp->fid.volume; *************** *** 1530,1544 **** lock_ObtainMutex(&dscp->mx); cm_dnlcRemove(dscp, namep); cm_SyncOpDone(dscp, NULL, sflags); ! if (code == 0) cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 0); ! else if (code == CM_ERROR_NOSUCHFILE) { /* windows would not have allowed the request to delete the file * if it did not believe the file existed. therefore, we must * have an inconsistent view of the world. */ dscp->cbServerp = NULL; } lock_ReleaseMutex(&dscp->mx); return code; --- 1590,1608 ---- lock_ObtainMutex(&dscp->mx); cm_dnlcRemove(dscp, namep); cm_SyncOpDone(dscp, NULL, sflags); ! if (code == 0) { cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 0); ! if (cm_CheckDirOpForSingleChange(&dirop)) { ! cm_DirDeleteEntry(&dirop, namep); ! } ! } else if (code == CM_ERROR_NOSUCHFILE) { /* windows would not have allowed the request to delete the file * if it did not believe the file existed. therefore, we must * have an inconsistent view of the world. */ dscp->cbServerp = NULL; } + cm_EndDirOp(&dirop); lock_ReleaseMutex(&dscp->mx); return code; *************** *** 1724,1729 **** --- 1788,1797 ---- int symlinkCount; /* count of # of symlinks traversed */ int extraFlag; /* avoid chasing mt pts for dir cmd */ int phase = 1; /* 1 = tidPathp, 2 = pathp */ + #define MAX_FID_COUNT 512 + cm_fid_t fids[MAX_FID_COUNT]; /* array of fids processed in this path walk */ + int fid_count = 0; /* number of fids processed in this path walk */ + int i; #ifdef DEBUG_REFCOUNT afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount); *************** *** 1787,1793 **** code = cm_Lookup(tscp, component, flags | extraFlag, userp, reqp, &nscp); ! if (code) { cm_ReleaseSCache(tscp); if (dirScp) cm_ReleaseSCache(dirScp); --- 1855,1876 ---- code = cm_Lookup(tscp, component, flags | extraFlag, userp, reqp, &nscp); ! ! if (code == 0) { ! for ( i=0; ifid, &fids[i]) ) { ! code = CM_ERROR_TOO_MANY_SYMLINKS; ! cm_ReleaseSCache(nscp); ! nscp = NULL; ! break; ! } ! } ! if (i == fid_count && fid_count < MAX_FID_COUNT) { ! fids[fid_count++] = nscp->fid; ! } ! } ! ! if (code) { cm_ReleaseSCache(tscp); if (dirScp) cm_ReleaseSCache(dirScp); *************** *** 1855,1860 **** --- 1938,1958 ---- else restp = tp; code = cm_AssembleLink(tscp, restp, &linkScp, &tempsp, userp, reqp); + + if (code == 0 && linkScp != NULL) { + for ( i=0; ifid, &fids[i]) ) { + code = CM_ERROR_TOO_MANY_SYMLINKS; + cm_ReleaseSCache(linkScp); + nscp = NULL; + break; + } + } + if (i == fid_count && fid_count < MAX_FID_COUNT) { + fids[fid_count++] = linkScp->fid; + } + } + if (code) { /* something went wrong */ cm_ReleaseSCache(tscp); *************** *** 1987,1992 **** --- 2085,2096 ---- cm_FreeSpace(spacep); cm_ReleaseSCache(newRootScp); + if (linkScp == *outScpp) { + cm_ReleaseSCache(*outScpp); + *outScpp = NULL; + code = CM_ERROR_NOSUCHPATH; + } + return code; } *************** *** 2461,2467 **** cm_callbackRequest_t cbReq; AFSFid newAFSFid; cm_fid_t newFid; ! cm_scache_t *scp; int didEnd; AFSStoreStatus inStatus; AFSFetchStatus updatedDirStatus; --- 2565,2571 ---- cm_callbackRequest_t cbReq; AFSFid newAFSFid; cm_fid_t newFid; ! cm_scache_t *scp = NULL; int didEnd; AFSStoreStatus inStatus; AFSFetchStatus updatedDirStatus; *************** *** 2469,2474 **** --- 2573,2579 ---- AFSCallBack newFileCallback; AFSVolSync volSync; struct rx_connection * callp; + cm_dirOp_t dirop; /* can't create names with @sys in them; must expand it manually first. * return "invalid request" if they try. *************** *** 2482,2490 **** --- 2587,2598 ---- * completes. */ lock_ObtainMutex(&dscp->mx); + cm_BeginDirOp(dscp, userp, reqp, &dirop); code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); if (code == 0) { cm_StartCallbackGrantingCall(NULL, &cbReq); + } else { + cm_EndDirOp(&dirop); } lock_ReleaseMutex(&dscp->mx); if (code) { *************** *** 2558,2563 **** --- 2666,2678 ---- if (!didEnd) cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0); + lock_ObtainMutex(&dscp->mx); + if (scp && cm_CheckDirOpForSingleChange(&dirop)) { + cm_DirCreateEntry(&dirop, namep, &newFid); + } + cm_EndDirOp(&dirop); + lock_ReleaseMutex(&dscp->mx); + return code; } *************** *** 2603,2608 **** --- 2718,2724 ---- AFSCallBack newDirCallback; AFSVolSync volSync; struct rx_connection * callp; + cm_dirOp_t dirop; /* can't create names with @sys in them; must expand it manually first. * return "invalid request" if they try. *************** *** 2616,2624 **** --- 2732,2743 ---- * our call completes. */ lock_ObtainMutex(&dscp->mx); + cm_BeginDirOp(dscp, userp, reqp, &dirop); code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); if (code == 0) { cm_StartCallbackGrantingCall(NULL, &cbReq); + } else { + cm_EndDirOp(&dirop); } lock_ReleaseMutex(&dscp->mx); if (code) { *************** *** 2691,2696 **** --- 2810,2822 ---- if (!didEnd) cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0); + lock_ObtainMutex(&dscp->mx); + if (scp && cm_CheckDirOpForSingleChange(&dirop)) { + cm_DirCreateEntry(&dirop, namep, &newFid); + } + cm_EndDirOp(&dirop); + lock_ReleaseMutex(&dscp->mx); + /* and return error code */ return code; } *************** *** 2706,2711 **** --- 2832,2838 ---- AFSFetchStatus newLinkStatus; AFSVolSync volSync; struct rx_connection * callp; + cm_dirOp_t dirop; if (dscp->fid.cell != sscp->fid.cell || dscp->fid.volume != sscp->fid.volume) { *************** *** 2713,2719 **** --- 2840,2849 ---- } lock_ObtainMutex(&dscp->mx); + cm_BeginDirOp(dscp, userp, reqp, &dirop); code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); + if (code != 0) + cm_EndDirOp(&dirop); lock_ReleaseMutex(&dscp->mx); if (code) *************** *** 2753,2759 **** --- 2883,2893 ---- cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA); if (code == 0) { cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0); + if (cm_CheckDirOpForSingleChange(&dirop)) { + cm_DirCreateEntry(&dirop, namep, &sscp->fid); + } } + cm_EndDirOp(&dirop); lock_ReleaseMutex(&dscp->mx); return code; *************** *** 2773,2785 **** --- 2907,2923 ---- AFSFetchStatus newLinkStatus; AFSVolSync volSync; struct rx_connection * callp; + cm_dirOp_t dirop; /* before starting the RPC, mark that we're changing the directory data, * so that someone who does a chmod on the dir will wait until our * call completes. */ lock_ObtainMutex(&dscp->mx); + cm_BeginDirOp(dscp, userp, reqp, &dirop); code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); + if (code != 0) + cm_EndDirOp(&dirop); lock_ReleaseMutex(&dscp->mx); if (code) { return code; *************** *** 2817,2823 **** --- 2955,2970 ---- cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA); if (code == 0) { cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0); + if (cm_CheckDirOpForSingleChange(&dirop)) { + newFid.cell = dscp->fid.cell; + newFid.volume = dscp->fid.volume; + newFid.vnode = newAFSFid.Vnode; + newFid.unique = newAFSFid.Unique; + + cm_DirCreateEntry(&dirop, namep, &newFid); + } } + cm_EndDirOp(&dirop); lock_ReleaseMutex(&dscp->mx); /* now try to create the new dir's entry, too, but be careful to *************** *** 2856,2872 **** AFSFetchStatus updatedDirStatus; AFSVolSync volSync; struct rx_connection * callp; /* before starting the RPC, mark that we're changing the directory data, * so that someone who does a chmod on the dir will wait until our * call completes. */ lock_ObtainMutex(&dscp->mx); code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); - lock_ReleaseMutex(&dscp->mx); if (code) { return code; } didEnd = 0; /* try the RPC now */ --- 3003,3023 ---- AFSFetchStatus updatedDirStatus; AFSVolSync volSync; struct rx_connection * callp; + cm_dirOp_t dirOp; /* before starting the RPC, mark that we're changing the directory data, * so that someone who does a chmod on the dir will wait until our * call completes. */ lock_ObtainMutex(&dscp->mx); + cm_BeginDirOp(dscp, userp, reqp, &dirOp); code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); if (code) { + cm_EndDirOp(&dirOp); + lock_ReleaseMutex(&dscp->mx); return code; } + lock_ReleaseMutex(&dscp->mx); didEnd = 0; /* try the RPC now */ *************** *** 2899,2905 **** --- 3050,3060 ---- if (code == 0) { cm_dnlcRemove(dscp, namep); cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0); + if (cm_CheckDirOpForSingleChange(&dirOp)) { + cm_DirDeleteEntry(&dirOp, namep); } + } + cm_EndDirOp(&dirOp); lock_ReleaseMutex(&dscp->mx); /* and return error code */ *************** *** 2937,2942 **** --- 3092,3101 ---- AFSVolSync volSync; int oneDir; struct rx_connection * callp; + cm_dirOp_t oldDirOp; + cm_fid_t fileFid; + int diropCode = -1; + cm_dirOp_t newDirOp; /* before starting the RPC, mark that we're changing the directory data, * so that someone who does a chmod on the dir will wait until our call *************** *** 2952,2959 **** --- 3111,3122 ---- lock_ObtainMutex(&oldDscp->mx); cm_dnlcRemove(oldDscp, oldNamep); cm_dnlcRemove(oldDscp, newNamep); + cm_BeginDirOp(oldDscp, userp, reqp, &oldDirOp); code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); + if (code != 0) { + cm_EndDirOp(&oldDirOp); + } lock_ReleaseMutex(&oldDscp->mx); } else { *************** *** 2972,2992 **** --- 3135,3162 ---- if (oldDscp->fid.vnode < newDscp->fid.vnode) { lock_ObtainMutex(&oldDscp->mx); + cm_BeginDirOp(oldDscp, userp, reqp, &oldDirOp); cm_dnlcRemove(oldDscp, oldNamep); code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); + if (code != 0) + cm_EndDirOp(&oldDirOp); lock_ReleaseMutex(&oldDscp->mx); if (code == 0) { lock_ObtainMutex(&newDscp->mx); + cm_BeginDirOp(newDscp, userp, reqp, &newDirOp); cm_dnlcRemove(newDscp, newNamep); code = cm_SyncOp(newDscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); + if (code != 0) + cm_EndDirOp(&newDirOp); lock_ReleaseMutex(&newDscp->mx); if (code) { /* cleanup first one */ lock_ObtainMutex(&oldDscp->mx); cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA); + cm_EndDirOp(&oldDirOp); lock_ReleaseMutex(&oldDscp->mx); } } *************** *** 2994,3014 **** --- 3164,3191 ---- else { /* lock the new vnode entry first */ lock_ObtainMutex(&newDscp->mx); + cm_BeginDirOp(newDscp, userp, reqp, &newDirOp); cm_dnlcRemove(newDscp, newNamep); code = cm_SyncOp(newDscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); + if (code != 0) + cm_EndDirOp(&newDirOp); lock_ReleaseMutex(&newDscp->mx); if (code == 0) { lock_ObtainMutex(&oldDscp->mx); + cm_BeginDirOp(oldDscp, userp, reqp, &oldDirOp); cm_dnlcRemove(oldDscp, oldNamep); code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA); + if (code != 0) + cm_EndDirOp(&oldDirOp); lock_ReleaseMutex(&oldDscp->mx); if (code) { /* cleanup first one */ lock_ObtainMutex(&newDscp->mx); cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA); + cm_EndDirOp(&newDirOp); lock_ReleaseMutex(&newDscp->mx); } } *************** *** 3054,3063 **** --- 3231,3257 ---- /* update the individual stat cache entries for the directories */ lock_ObtainMutex(&oldDscp->mx); cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA); + if (code == 0) { cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync, userp, 0); + + if (cm_CheckDirOpForSingleChange(&oldDirOp)) { + + diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid); + + if (diropCode == 0) { + if (oneDir) { + diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid); + } + + if (diropCode == 0) { + diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep); } + } + } + } + cm_EndDirOp(&oldDirOp); lock_ReleaseMutex(&oldDscp->mx); /* and update it for the new one, too, if necessary */ *************** *** 3067,3073 **** --- 3261,3275 ---- if (code == 0) { cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync, userp, 0); + + /* we only make the local change if we successfully made + the change in the old directory AND there was only one + change in the new directory */ + if (diropCode == 0 && cm_CheckDirOpForSingleChange(&newDirOp)) { + cm_DirCreateEntry(&newDirOp, newNamep, &fileFid); + } } + cm_EndDirOp(&newDirOp); lock_ReleaseMutex(&newDscp->mx); } Index: openafs/src/WINNT/afsd/fs.c diff -c openafs/src/WINNT/afsd/fs.c:1.32.4.11 openafs/src/WINNT/afsd/fs.c:1.32.4.12 *** openafs/src/WINNT/afsd/fs.c:1.32.4.11 Mon Jul 2 20:35:13 2007 --- openafs/src/WINNT/afsd/fs.c Fri Jul 27 23:04:37 2007 *************** *** 1099,1105 **** blob.out = cellname; code = pioctl(fname, VIOC_FILE_CELL_NAME, &blob, 1); ! return code ? errno : 0; } /* Check if a username is valid: If it contains only digits (or a --- 1099,1105 ---- blob.out = cellname; code = pioctl(fname, VIOC_FILE_CELL_NAME, &blob, 1); ! return code; } /* Check if a username is valid: If it contains only digits (or a *************** *** 1930,1937 **** cellName = localCellName; } } else { ! if (!cellName) ! GetCell(parent,space); } code = GetCellName(cellName?cellName:space, &info); --- 1930,1940 ---- cellName = localCellName; } } else { ! if (!cellName) { ! code = GetCell(parent,space); ! if (code) ! return 1; ! } } code = GetCellName(cellName?cellName:space, &info); Index: openafs/src/WINNT/afsd/rawops.c diff -c openafs/src/WINNT/afsd/rawops.c:1.2.4.2 openafs/src/WINNT/afsd/rawops.c:1.2.4.3 *** openafs/src/WINNT/afsd/rawops.c:1.2.4.2 Mon Dec 11 23:01:26 2006 --- openafs/src/WINNT/afsd/rawops.c Thu Aug 9 01:33:56 2007 *************** *** 155,165 **** long written = 0; osi_hyper_t fileLength; /* file's length at start of write */ osi_hyper_t minLength; /* don't read past this */ ! long nbytes; /* # of bytes to transfer this iteration */ cm_buf_t *bufferp; osi_hyper_t thyper; /* hyper tmp variable */ osi_hyper_t bufferOffset; ! long bufIndex; /* index in buffer where our data is */ int doWriteBack; osi_hyper_t writeBackOffset; /* offset of region to write back when * I/O is done */ --- 155,165 ---- long written = 0; osi_hyper_t fileLength; /* file's length at start of write */ osi_hyper_t minLength; /* don't read past this */ ! afs_uint32 nbytes; /* # of bytes to transfer this iteration */ cm_buf_t *bufferp; osi_hyper_t thyper; /* hyper tmp variable */ osi_hyper_t bufferOffset; ! afs_uint32 bufIndex; /* index in buffer where our data is */ int doWriteBack; osi_hyper_t writeBackOffset; /* offset of region to write back when * I/O is done */ *************** *** 333,339 **** else #endif /* DJGPP */ memcpy(bufferp->datap + bufIndex, op, nbytes); ! buf_SetDirty(bufferp); /* and record the last writer */ if (bufferp->userp != userp) { --- 333,339 ---- else #endif /* DJGPP */ memcpy(bufferp->datap + bufIndex, op, nbytes); ! buf_SetDirty(bufferp, bufIndex, nbytes); /* and record the last writer */ if (bufferp->userp != userp) { Index: openafs/src/WINNT/afsd/smb.c diff -c openafs/src/WINNT/afsd/smb.c:1.118.2.37 openafs/src/WINNT/afsd/smb.c:1.118.2.40 *** openafs/src/WINNT/afsd/smb.c:1.118.2.37 Thu Jul 5 15:22:16 2007 --- openafs/src/WINNT/afsd/smb.c Thu Aug 9 01:33:56 2007 *************** *** 4389,4395 **** scp->bulkStatProgress)) { /* Don't bulk stat if risking timeout */ int now = GetTickCount(); ! if (now - req.startTime > RDRtimeout) { scp->bulkStatProgress = thyper; scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING; dsp->flags &= ~SMB_DIRSEARCH_BULKST; --- 4389,4395 ---- scp->bulkStatProgress)) { /* Don't bulk stat if risking timeout */ int now = GetTickCount(); ! if (now - req.startTime > RDRtimeout * 1000) { scp->bulkStatProgress = thyper; scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING; dsp->flags &= ~SMB_DIRSEARCH_BULKST; *************** *** 5182,5187 **** --- 5182,5188 ---- char *maskp; /* pointer to the star pattern */ int flags; int any; + cm_dirEntryList_t * matches; } smb_unlinkRock_t; int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) *************** *** 5210,5229 **** match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD); } if (match) { ! osi_Log1(smb_logp, "Unlinking %s", osi_LogSaveString(smb_logp, matchName)); ! code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp); ! if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH)) ! smb_NotifyChange(FILE_ACTION_REMOVED, ! FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION, ! dscp, dep->name, NULL, TRUE); ! if (code == 0) { rockp->any = 1; /* If we made a case sensitive exact match, we might as well quit now. */ if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp)) code = CM_ERROR_STOPNOW; ! } } else code = 0; --- 5211,5228 ---- match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD); } if (match) { ! osi_Log1(smb_logp, "Found match %s", osi_LogSaveString(smb_logp, matchName)); ! ! cm_DirEntryListAdd(dep->name, &rockp->matches); ! rockp->any = 1; /* If we made a case sensitive exact match, we might as well quit now. */ if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp)) code = CM_ERROR_STOPNOW; ! else ! code = 0; } else code = 0; *************** *** 5304,5309 **** --- 5303,5309 ---- rock.reqp = &req; rock.dscp = dscp; rock.vcp = vcp; + rock.matches = NULL; /* Now, if we aren't dealing with a wildcard match, we first try an exact * match. If that fails, we do a case insensitve match. *************** *** 5324,5329 **** --- 5324,5347 ---- if (code == CM_ERROR_STOPNOW) code = 0; + if (code == 0 && rock.matches) { + cm_dirEntryList_t * entry; + + for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) { + + osi_Log1(smb_logp, "Unlinking %s", + osi_LogSaveString(smb_logp, entry->name)); + code = cm_Unlink(dscp, entry->name, userp, &req); + + if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH)) + smb_NotifyChange(FILE_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION, + dscp, entry->name, NULL, TRUE); + } + } + + cm_DirEntryListFree(&rock.matches); + cm_ReleaseUser(userp); cm_ReleaseSCache(dscp); *************** *** 5342,5347 **** --- 5360,5366 ---- char *maskp; /* pointer to star pattern of old file name */ int flags; /* tilde, casefold, etc */ char *newNamep; /* ptr to the new file's name */ + char oldName[MAX_PATH]; int any; } smb_renameRock_t; *************** *** 5366,5386 **** cm_Gen8Dot3Name(dep, shortName, NULL); match = smb_V3MatchMask(shortName, rockp->maskp, caseFold); } if (match) { rockp->any = 1; ! ! code = cm_Rename(rockp->odscp, dep->name, ! rockp->ndscp, rockp->newNamep, rockp->userp, ! rockp->reqp); ! /* if the call worked, stop doing the search now, since we ! * really only want to rename one file. ! */ ! osi_Log1(smb_logp, "cm_Rename returns %ld", code); ! if (code == 0) code = CM_ERROR_STOPNOW; ! } ! else code = 0; return code; } --- 5385,5399 ---- cm_Gen8Dot3Name(dep, shortName, NULL); match = smb_V3MatchMask(shortName, rockp->maskp, caseFold); } + if (match) { rockp->any = 1; ! strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1); ! rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0'; code = CM_ERROR_STOPNOW; ! } else { code = 0; + } return code; } *************** *** 5485,5490 **** --- 5498,5504 ---- rock.maskp = oldLastNamep; rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0); rock.newNamep = newLastNamep; + rock.oldName[0] = '\0'; rock.any = 0; /* Check if the file already exists; if so return error */ *************** *** 5537,5552 **** } osi_Log1(smb_logp, "smb_RenameProc returns %ld", code); ! if (code == CM_ERROR_STOPNOW) ! code = 0; ! else if (code == 0) code = CM_ERROR_NOSUCHFILE; /* Handle Change Notification */ /* * Being lazy, not distinguishing between files and dirs in this * filter, since we'd have to do a lookup. */ filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME; if (oldDscp == newDscp) { if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH) --- 5551,5574 ---- } osi_Log1(smb_logp, "smb_RenameProc returns %ld", code); ! if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') { ! code = cm_Rename(rock.odscp, rock.oldName, ! rock.ndscp, rock.newNamep, rock.userp, ! rock.reqp); ! /* if the call worked, stop doing the search now, since we ! * really only want to rename one file. ! */ ! osi_Log1(smb_logp, "cm_Rename returns %ld", code); ! } else if (code == 0) { code = CM_ERROR_NOSUCHFILE; + } /* Handle Change Notification */ /* * Being lazy, not distinguishing between files and dirs in this * filter, since we'd have to do a lookup. */ + if (code == 0) { filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME; if (oldDscp == newDscp) { if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH) *************** *** 5563,5568 **** --- 5585,5591 ---- filter, newDscp, newLastNamep, NULL, TRUE); } + } if (tmpscp != NULL) cm_ReleaseSCache(tmpscp); *************** *** 5759,5764 **** --- 5782,5788 ---- char *maskp; /* pointer to the star pattern */ int flags; int any; + cm_dirEntryList_t * matches; } smb_rmdirRock_t; int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) *************** *** 5783,5802 **** matchName = shortName; match = (cm_stricmp(matchName, rockp->maskp) == 0); } if (match) { - osi_Log1(smb_logp, "Removing directory %s", - osi_LogSaveString(smb_logp, matchName)); - code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp); - if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH)) - smb_NotifyChange(FILE_ACTION_REMOVED, - FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION, - dscp, dep->name, NULL, TRUE); - if (code == 0) rockp->any = 1; } - else code = 0; ! return code; } long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) --- 5807,5819 ---- matchName = shortName; match = (cm_stricmp(matchName, rockp->maskp) == 0); } + if (match) { rockp->any = 1; + cm_DirEntryListAdd(dep->name, &rockp->matches); } ! return 0; } long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) *************** *** 5867,5872 **** --- 5884,5890 ---- rock.userp = userp; rock.reqp = &req; rock.dscp = dscp; + rock.matches = NULL; /* First do a case sensitive match, and if that fails, do a case insensitive match */ code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL); *************** *** 5877,5882 **** --- 5895,5918 ---- code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL); } + if (code == 0 && rock.matches) { + cm_dirEntryList_t * entry; + + for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) { + osi_Log1(smb_logp, "Removing directory %s", + osi_LogSaveString(smb_logp, entry->name)); + + code = cm_RemoveDir(dscp, entry->name, userp, &req); + + if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH)) + smb_NotifyChange(FILE_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION, + dscp, entry->name, NULL, TRUE); + } + } + + cm_DirEntryListFree(&rock.matches); + cm_ReleaseUser(userp); cm_ReleaseSCache(dscp); *************** *** 6381,6391 **** cm_scache_t *scp; osi_hyper_t fileLength; /* file's length at start of write */ osi_hyper_t minLength; /* don't read past this */ ! long nbytes; /* # of bytes to transfer this iteration */ cm_buf_t *bufferp; osi_hyper_t thyper; /* hyper tmp variable */ osi_hyper_t bufferOffset; ! long bufIndex; /* index in buffer where our data is */ int doWriteBack; osi_hyper_t writeBackOffset;/* offset of region to write back when * I/O is done */ --- 6417,6427 ---- cm_scache_t *scp; osi_hyper_t fileLength; /* file's length at start of write */ osi_hyper_t minLength; /* don't read past this */ ! afs_uint32 nbytes; /* # of bytes to transfer this iteration */ cm_buf_t *bufferp; osi_hyper_t thyper; /* hyper tmp variable */ osi_hyper_t bufferOffset; ! afs_uint32 bufIndex; /* index in buffer where our data is */ int doWriteBack; osi_hyper_t writeBackOffset;/* offset of region to write back when * I/O is done */ *************** *** 6572,6578 **** else #endif /* DJGPP */ memcpy(bufferp->datap + bufIndex, op, nbytes); ! buf_SetDirty(bufferp); /* and record the last writer */ if (bufferp->userp != userp) { --- 6608,6614 ---- else #endif /* DJGPP */ memcpy(bufferp->datap + bufIndex, op, nbytes); ! buf_SetDirty(bufferp, bufIndex, nbytes); /* and record the last writer */ if (bufferp->userp != userp) { Index: openafs/src/WINNT/afsd/smb3.c diff -c openafs/src/WINNT/afsd/smb3.c:1.95.2.38 openafs/src/WINNT/afsd/smb3.c:1.95.2.40 *** openafs/src/WINNT/afsd/smb3.c:1.95.2.38 Sat Jun 30 00:38:52 2007 --- openafs/src/WINNT/afsd/smb3.c Fri Jul 27 22:51:16 2007 *************** *** 4337,4343 **** userp = smb_GetTran2User(vcp, p); if (!userp) { ! osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid); smb_FreeTran2Packet(outp); return CM_ERROR_BADSMB; } --- 4337,4343 ---- userp = smb_GetTran2User(vcp, p); if (!userp) { ! osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid); smb_FreeTran2Packet(outp); return CM_ERROR_BADSMB; } *************** *** 4378,4390 **** return 0; } #endif /* DFS_SUPPORT */ ! osi_Log1(smb_logp,"smb_ReceiveTran2SearchDir scp 0x%p", scp); ! lock_ObtainMutex(&scp->mx); ! if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 && ! LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) { ! scp->flags |= CM_SCACHEFLAG_BULKSTATTING; ! } ! lock_ReleaseMutex(&scp->mx); /* now do a single case sensitive lookup for the file in question */ code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp); --- 4378,4384 ---- return 0; } #endif /* DFS_SUPPORT */ ! osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp); /* now do a single case sensitive lookup for the file in question */ code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp); *************** *** 4984,4990 **** LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) { /* Don't bulk stat if risking timeout */ DWORD now = GetTickCount(); ! if (now - req.startTime > RDRtimeout) { scp->bulkStatProgress = thyper; scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING; dsp->flags &= ~SMB_DIRSEARCH_BULKST; --- 4978,4984 ---- LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) { /* Don't bulk stat if risking timeout */ DWORD now = GetTickCount(); ! if (now - req.startTime > RDRtimeout * 1000) { scp->bulkStatProgress = thyper; scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING; dsp->flags &= ~SMB_DIRSEARCH_BULKST; Index: openafs/src/WINNT/aklog/aklog.c diff -c openafs/src/WINNT/aklog/aklog.c:1.14.4.4 openafs/src/WINNT/aklog/aklog.c:1.14.4.5 *** openafs/src/WINNT/aklog/aklog.c:1.14.4.4 Tue May 15 23:34:58 2007 --- openafs/src/WINNT/aklog/aklog.c Thu Aug 9 18:54:07 2007 *************** *** 220,235 **** } /* - * This is a crock, but it is Transarc's crock, so - * we have to play along in order to get the - * functionality. The way the afs id is stored is - * as a string in the username field of the token. - * Contrary to what you may think by looking at - * the code for tokens, this hack (AFS ID %d) will - * not work if you change %d to something else. - */ - - /* * This code is taken from cklog -- it lets people * automatically register with the ptserver in foreign cells */ --- 220,225 ---- *************** *** 266,272 **** } if ((*status = ktc_SetToken(aserver, atoken, aclient, 0))) { ! printf("%s: unable to obtain tokens for cell %s " "(status: %d).\n", progname, cell_to_use, status); *status = AKLOG_TOKEN; return ; --- 256,262 ---- } if ((*status = ktc_SetToken(aserver, atoken, aclient, 0))) { ! printf("%s: unable to set tokens for cell %s " "(status: %d).\n", progname, cell_to_use, status); *status = AKLOG_TOKEN; return ; Index: openafs/src/WINNT/client_config/lang/en_US/afs_config.rc diff -c openafs/src/WINNT/client_config/lang/en_US/afs_config.rc:1.7.6.3 openafs/src/WINNT/client_config/lang/en_US/afs_config.rc:1.7.6.4 *** openafs/src/WINNT/client_config/lang/en_US/afs_config.rc:1.7.6.3 Fri Feb 2 23:53:04 2007 --- openafs/src/WINNT/client_config/lang/en_US/afs_config.rc Fri Jul 27 11:41:53 2007 *************** *** 700,706 **** IDS_SERVICE_FAIL_START "The AFS Client Service could not be started successfully. You might not have authorization to perform this operation.\n\nError 0x%1." IDS_SERVICE_FAIL_STOP "The AFS Client Service could not be stopped successfully. You might not have authorization to perform this operation.\n\nError 0x%1." IDS_WARN_STOPPED "The disabled controls cannot be changed because the AFS Client service is not running." ! IDS_WARN_ADMIN "The disabled controls cannot be changed because you are not logged in to Windows as an administrator." IDS_CELL_UNKNOWN "(unknown)" IDS_GATEWAY_UNKNOWN "(unknown)" END --- 700,706 ---- IDS_SERVICE_FAIL_START "The AFS Client Service could not be started successfully. You might not have authorization to perform this operation.\n\nError 0x%1." IDS_SERVICE_FAIL_STOP "The AFS Client Service could not be stopped successfully. You might not have authorization to perform this operation.\n\nError 0x%1." IDS_WARN_STOPPED "The disabled controls cannot be changed because the AFS Client service is not running." ! IDS_WARN_ADMIN "The disabled controls cannot be changed because you are not a member of the AFS Administrators Group." IDS_CELL_UNKNOWN "(unknown)" IDS_GATEWAY_UNKNOWN "(unknown)" END Index: openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm diff -c openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm:1.5.4.16 openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm:1.5.4.17 *** openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm:1.5.4.16 Fri Jun 22 10:40:12 2007 --- openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm Thu Aug 9 11:46:17 2007 *************** *** 57,63 ****

OpenAFS for Windows

!

Version 1.5.21

 

--- 57,63 ----

OpenAFS for Windows

!

Version 1.5.22

 

*************** *** 80,86 **** ·         OpenAFS for Windows 1.5.21 Release Notes

--- 80,86 ---- ·         OpenAFS for Windows 1.5.22 Release Notes

Index: openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm diff -c openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm:1.1.6.16 openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm:1.1.6.17 *** openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm:1.1.6.16 Fri Jun 22 10:18:39 2007 --- openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm Thu Aug 9 11:46:21 2007 *************** *** 18,24 **** .shape {behavior:url(#default#VML);} ! OpenAFS for Windows 1.5.21 Release Notes ! OpenAFS for Windows 1.5.22 Release Notes ! OpenAFS for Windows 1.5.21 Release Notes ! OpenAFS for Windows 1.5.22 Release Notes !

OpenAFS for Windows 1.5.21
Release Notes

The Andrew File System (AFS) is a location-independent --- 586,592 ----

!

OpenAFS for Windows 1.5.22
Release Notes

The Andrew File System (AFS) is a location-independent *************** *** 646,652 **** Operational Notes. 2

!

4. How to Debug Problems with OpenAFS for Windows: 11

--- 646,652 ---- Operational Notes. 2

!

4. How to Debug Problems with OpenAFS for Windows: 11

*************** *** 1160,1166 ****

Integrated Login supports the ability to obtain tokens for multiple cells.  For further information on how to configure this feature ! read about the TheseCells value.

Integrated Login supports the ability to obtain tokens for multiple cells.  For further information on how to configure this feature ! read about the TheseCells value.

+

Known issues include lack of support for power management + and dynamic network configuration.

+

3.10.1. OpenAFS Server Installation

When the OpenAFS Server is installed, the 3.12. ! Large Files (64-bit) Supported

As of release 1.5.3, OpenAFS for Windows supports files larger than 2GB.  The maximum file size is now 16777216 terabytes when the --- 1493,1499 ---- name="_Toc115416118">3.12. ! Large File (64-bit) Support

As of release 1.5.3, OpenAFS for Windows supports files larger than 2GB.  The maximum file size is now 16777216 terabytes when the *************** *** 2100,2116 **** name="_Toc115416144">3.38. ! AFS Client Universally Unique Identifiers

The OpenAFS Client implements Universally Unique Identifiers ! (UUIDs).  They are used to provide the server with a method of identifying the client that is independent of IP ! address.  The UUID is generated when the AFSCache ! file is created and is maintained as long as the contents of the AFSCache file are kept intact.  The UUID is stored in ! the AFSCache file.   When cloning machines ! that have Windows AFS client installed, the AFSCache ! files should be deleted as part of the cloning process.

3.38. ! AFS Client Universally Unique Identifiers (UUIDs) vs. System Cloning

The OpenAFS Client implements Universally Unique Identifiers ! (UUIDs).  They are used to provide the AFS file server with a method of identifying the client that is independent of IP ! address.  This permits the AFS file server to track mobile clients or those ! behind Network Address Translators when they move from address to address or port ! to port. Tracking the client improves client performance by permitting callback ! state to be maintained across location changes. The UUID is generated when the ! AFSCache file is created and is maintained as long as ! the contents of the AFSCache file are valid.  ! The UUID is stored in the AFSCache file. 

!

! When cloning machines that have Windows AFS client installed it is necessary ! to generate a new UUID for each client. This will be done automatically if ! the Windows Machine SID is re-generated using Microsoft SysPrep. If the SID is ! not being re-generated either the AFSCache file should ! be deleted or the command fs uuid -generate must be executed after the ! the clone is created. Multiple AFS clients reporting the same UUID will not ! only result in horrible AFS client performance and cache inconsistencies, but ! they will also put a tremendous strain on the AFS file servers.

!

For lab environments that wish to erase all cached data ! on each restart, the NonPersistentCaching option ! will disable the use of the persistent cache file. As a side effect, a new ! UUID will be generated for the AFS client service on each restart.

The CIFS session timeout defaults to 45 seconds and can be ! increased by modifying the registry.

The CIFS session timeout defaults to 45 seconds and can be ! increased by modifying the registry.

bug reports.

4.5. Microsoft MiniDumps