static int afs_DisconCreateSymlink(struct vcache *avc, char *aname, struct vrequest *areq) { struct dcache *tdc; struct osi_file *tfile; afs_size_t offset, len; tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 0); if (!tdc) { /* printf("afs_DisconCreateSymlink: can't get new dcache for symlink.\n"); */ return ENETDOWN; } len = strlen(aname); avc->f.m.Length = len; ObtainWriteLock(&tdc->lock, 720); afs_AdjustSize(tdc, len); tdc->validPos = len; tfile = afs_CFileOpen(&tdc->f.inode); afs_CFileWrite(tfile, 0, aname, len); afs_CFileClose(tfile); ReleaseWriteLock(&tdc->lock); return 0; }
int DNew(struct dcache *adc, int page, struct DirBuffer *entry) { /* Same as read, only do *not* even try to read the page, since it * probably doesn't exist. */ struct buffer *tb; AFS_STATCNT(DNew); ObtainWriteLock(&afs_bufferLock, 264); if ((tb = afs_newslot(adc, page, NULL)) == 0) { ReleaseWriteLock(&afs_bufferLock); return EIO; } /* extend the chunk, if needed */ /* Do it now, not in DFlush or afs_newslot when the data is written out, * since now our caller has adc->lock writelocked, and we can't acquire * that lock (or even map from a fid to a dcache) in afs_newslot or * DFlush due to lock hierarchy issues */ if ((page + 1) * AFS_BUFFER_PAGESIZE > adc->f.chunkBytes) { afs_AdjustSize(adc, (page + 1) * AFS_BUFFER_PAGESIZE); osi_Assert(afs_WriteDCache(adc, 1) == 0); } ObtainWriteLock(&tb->lock, 265); tb->lockers++; ReleaseWriteLock(&afs_bufferLock); ReleaseWriteLock(&tb->lock); entry->buffer = tb; entry->data = tb->data; return 0; }
/*! * * Extend a cache file * * \param avc pointer to vcache to extend data for * \param alen Length to extend file to * \param areq * * \note avc must be write locked. May release and reobtain avc and GLOCK */ int afs_ExtendSegments(struct vcache *avc, afs_size_t alen, struct vrequest *areq) { afs_size_t offset, toAdd; struct osi_file *tfile; afs_int32 code = 0; struct dcache *tdc; void *zeros; zeros = afs_osi_Alloc(AFS_PAGESIZE); if (zeros == NULL) return ENOMEM; memset(zeros, 0, AFS_PAGESIZE); while (avc->f.m.Length < alen) { tdc = afs_ObtainDCacheForWriting(avc, avc->f.m.Length, alen - avc->f.m.Length, areq, 0); if (!tdc) { code = EIO; break; } toAdd = alen - avc->f.m.Length; offset = avc->f.m.Length - AFS_CHUNKTOBASE(tdc->f.chunk); if (offset + toAdd > AFS_CHUNKTOSIZE(tdc->f.chunk)) { toAdd = AFS_CHUNKTOSIZE(tdc->f.chunk) - offset; } tfile = afs_CFileOpen(&tdc->f.inode); while(tdc->validPos < avc->f.m.Length + toAdd) { afs_size_t towrite; towrite = (avc->f.m.Length + toAdd) - tdc->validPos; if (towrite > AFS_PAGESIZE) towrite = AFS_PAGESIZE; code = afs_CFileWrite(tfile, tdc->validPos - AFS_CHUNKTOBASE(tdc->f.chunk), zeros, towrite); tdc->validPos += towrite; } afs_CFileClose(tfile); afs_AdjustSize(tdc, offset + toAdd ); avc->f.m.Length += toAdd; ReleaseWriteLock(&tdc->lock); afs_PutDCache(tdc); } afs_osi_Free(zeros, AFS_PAGESIZE); return code; }
/* * afs_TruncateAllSegments * * Description: * Truncate a cache file. * * Parameters: * avc : Ptr to vcache entry to truncate. * alen : Number of bytes to make the file. * areq : Ptr to request structure. * * Environment: * Called with avc write-locked; in VFS40 systems, pvnLock is also * held. */ int afs_TruncateAllSegments(struct vcache *avc, afs_size_t alen, struct vrequest *areq, afs_ucred_t *acred) { struct dcache *tdc; afs_int32 code; afs_int32 index; afs_size_t newSize; int dcCount, dcPos; struct dcache **tdcArray = NULL; AFS_STATCNT(afs_TruncateAllSegments); avc->f.m.Date = osi_Time(); afs_Trace3(afs_iclSetp, CM_TRACE_TRUNCALL, ICL_TYPE_POINTER, avc, ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(alen)); if (alen >= avc->f.m.Length) { /* * Special speedup since Sun's vm extends the file this way; * we've never written to the file thus we can just set the new * length and avoid the needless calls below. * Also used for ftruncate calls which can extend the file. * To completely minimize the possible extra StoreMini RPC, we really * should keep the ExtendedPos as well and clear this flag if we * truncate below that value before we store the file back. */ avc->f.states |= CExtendedFile; avc->f.m.Length = alen; return 0; } #if (defined(AFS_SUN5_ENV)) /* Zero unused portion of last page */ osi_VM_PreTruncate(avc, alen, acred); #endif #if (defined(AFS_SUN5_ENV)) ObtainWriteLock(&avc->vlock, 546); avc->activeV++; /* Block new getpages */ ReleaseWriteLock(&avc->vlock); #endif ReleaseWriteLock(&avc->lock); AFS_GUNLOCK(); /* Flush pages beyond end-of-file. */ osi_VM_Truncate(avc, alen, acred); AFS_GLOCK(); ObtainWriteLock(&avc->lock, 79); avc->f.m.Length = alen; if (alen < avc->f.truncPos) avc->f.truncPos = alen; code = DVHash(&avc->f.fid); /* block out others from screwing with this table */ ObtainWriteLock(&afs_xdcache, 287); dcCount = 0; for (index = afs_dvhashTbl[code]; index != NULLIDX;) { if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) { tdc = afs_GetValidDSlot(index); if (!tdc) { ReleaseWriteLock(&afs_xdcache); code = EIO; goto done; } ReleaseReadLock(&tdc->tlock); if (!FidCmp(&tdc->f.fid, &avc->f.fid)) dcCount++; afs_PutDCache(tdc); } index = afs_dvnextTbl[index]; } /* Now allocate space where we can save those dcache entries, and * do a second pass over them.. Since we're holding xdcache, it * shouldn't be changing. */ tdcArray = osi_Alloc(dcCount * sizeof(struct dcache *)); dcPos = 0; for (index = afs_dvhashTbl[code]; index != NULLIDX; index = afs_dvnextTbl[index]) { if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) { tdc = afs_GetValidDSlot(index); if (!tdc) { /* make sure we put back all of the tdcArray members before * bailing out */ /* remember, the last valid tdc is at dcPos-1, so start at * dcPos-1, not at dcPos itself. */ for (dcPos = dcPos - 1; dcPos >= 0; dcPos--) { tdc = tdcArray[dcPos]; afs_PutDCache(tdc); } code = EIO; goto done; } ReleaseReadLock(&tdc->tlock); if (!FidCmp(&tdc->f.fid, &avc->f.fid)) { /* same file, and modified, we'll store it back */ if (dcPos < dcCount) { tdcArray[dcPos++] = tdc; } else { afs_PutDCache(tdc); } } else { afs_PutDCache(tdc); } } } ReleaseWriteLock(&afs_xdcache); /* Now we loop over the array of dcache entries and truncate them */ for (index = 0; index < dcPos; index++) { struct osi_file *tfile; tdc = tdcArray[index]; newSize = alen - AFS_CHUNKTOBASE(tdc->f.chunk); if (newSize < 0) newSize = 0; ObtainSharedLock(&tdc->lock, 672); if (newSize < tdc->f.chunkBytes && newSize < MAX_AFS_UINT32) { UpgradeSToWLock(&tdc->lock, 673); tdc->f.states |= DWriting; tfile = afs_CFileOpen(&tdc->f.inode); afs_CFileTruncate(tfile, (afs_int32)newSize); afs_CFileClose(tfile); afs_AdjustSize(tdc, (afs_int32)newSize); if (alen < tdc->validPos) { if (alen < AFS_CHUNKTOBASE(tdc->f.chunk)) tdc->validPos = 0; else tdc->validPos = alen; } ConvertWToSLock(&tdc->lock); } ReleaseSharedLock(&tdc->lock); afs_PutDCache(tdc); } code = 0; done: if (tdcArray) { osi_Free(tdcArray, dcCount * sizeof(struct dcache *)); } #if (defined(AFS_SUN5_ENV)) ObtainWriteLock(&avc->vlock, 547); if (--avc->activeV == 0 && (avc->vstates & VRevokeWait)) { avc->vstates &= ~VRevokeWait; afs_osi_Wakeup((char *)&avc->vstates); } ReleaseWriteLock(&avc->vlock); #endif return code; }