void Quaternion_Matrix_Fourier_Transform_ExpLeft_Inv(Quaternion ** QMatrix,Quaternion *** pQMatrixFT, Quaternion QMu,int intHeight,int intWidth) { int s,t,S,T; Quaternion QExp,QSum; double dblFactor,dblQuotient; dblFactor = 2. * M_PI ; dblQuotient = sqrt((double)intHeight*(double)intWidth); // the frequency image coordinates will be describe // by the S and T index. // In the spatial image, the pixel will be pointed by the spatial // coordinates s and t. for (s=0;s<intHeight;s++) for (t=0;t<intWidth;t++) { QSum = QInit(0.,0.,0.,0.); //QDisp(QSum,stdout); for(S=0;S<intHeight;S++) { for(T=0;T<intWidth;T++) { QExp = QInitExp(QMu,dblFactor*(S*s/((double)intHeight)+T*t/((double)intWidth))); //QDisp(QExp,stdout); QSum = QAdd(QSum,QMult(QExp,QMatrix[S][T])); } } (*pQMatrixFT)[s][t].a = QSum.a/dblQuotient; (*pQMatrixFT)[s][t].b = QSum.b/dblQuotient; // R(s,t) (*pQMatrixFT)[s][t].c = QSum.c/dblQuotient; // G(s,t) (*pQMatrixFT)[s][t].d = QSum.d/dblQuotient; // B(s,t) } }
/*! * Bump given cell up to the front of the LRU queue. * \param c Cell to set. */ static void afs_UpdateCellLRU(struct cell *c) { ObtainWriteLock(&afs_xcell, 100); QRemove(&c->lruq); QAdd(&CellLRU, &c->lruq); ReleaseWriteLock(&afs_xcell); }
void afs_QueueCallback(struct vcache *avc, unsigned int atime, struct volume *avp) { if (avp && (avp->expireTime < avc->cbExpires)) avp->expireTime = avc->cbExpires; if (!(avc->callsort.next)) { atime = (atime + base) % CBHTSIZE; QAdd(&(cbHashT[atime].head), &(avc->callsort)); } return; } /* afs_QueueCallback */
/*! * Create or update a cell entry. * \param acellName Name of cell. * \param acellHosts Array of hosts that this cell has. * \param aflags Cell flags. * \param linkedcname * \param fsport File server port. * \param vlport Volume server port. * \param timeout Cell timeout value, 0 means static AFSDB entry. * \return */ afs_int32 afs_NewCell(char *acellName, afs_int32 * acellHosts, int aflags, char *linkedcname, u_short fsport, u_short vlport, int timeout) { struct cell *tc, *tcl = 0; afs_int32 i, newc = 0, code = 0; AFS_STATCNT(afs_NewCell); ObtainWriteLock(&afs_xcell, 103); tc = afs_FindCellByName_nl(acellName, READ_LOCK); if (tc) { aflags &= ~CNoSUID; } else { tc = afs_osi_Alloc(sizeof(struct cell)); osi_Assert(tc != NULL); memset(tc, 0, sizeof(*tc)); tc->cellName = afs_strdup(acellName); tc->fsport = AFS_FSPORT; tc->vlport = AFS_VLPORT; AFS_MD5_String(tc->cellHandle, tc->cellName, strlen(tc->cellName)); AFS_RWLOCK_INIT(&tc->lock, "cell lock"); newc = 1; aflags |= CNoSUID; } ObtainWriteLock(&tc->lock, 688); /* If the cell we've found has the correct name but no timeout, * and we're called with a non-zero timeout, bail out: never * override static configuration entries with AFSDB ones. * One exception: if the original cell entry had no servers, * it must get servers from AFSDB. */ if (timeout && !tc->timeout && tc->cellHosts[0]) { code = EEXIST; /* This code is checked for in afs_LookupAFSDB */ goto bad; } /* we don't want to keep pinging old vlservers which were down, * since they don't matter any more. It's easier to do this than * to remove the server from its various hash tables. */ for (i = 0; i < AFS_MAXCELLHOSTS; i++) { if (!tc->cellHosts[i]) break; tc->cellHosts[i]->flags &= ~SRVR_ISDOWN; tc->cellHosts[i]->flags |= SRVR_ISGONE; } if (fsport) tc->fsport = fsport; if (vlport) tc->vlport = vlport; if (aflags & CLinkedCell) { if (!linkedcname) { code = EINVAL; goto bad; } tcl = afs_FindCellByName_nl(linkedcname, READ_LOCK); if (!tcl) { code = ENOENT; goto bad; } if (tcl->lcellp) { /* XXX Overwriting if one existed before! XXX */ tcl->lcellp->lcellp = (struct cell *)0; tcl->lcellp->states &= ~CLinkedCell; } tc->lcellp = tcl; tcl->lcellp = tc; } tc->states |= aflags; tc->timeout = timeout; memset(tc->cellHosts, 0, sizeof(tc->cellHosts)); for (i = 0; i < AFS_MAXCELLHOSTS; i++) { /* Get server for each host and link this cell in.*/ struct server *ts; afs_uint32 temp = acellHosts[i]; if (!temp) break; ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, NULL, 0); ts->cell = tc; ts->flags &= ~SRVR_ISGONE; /* Set the server as a host of the new cell. */ tc->cellHosts[i] = ts; afs_PutServer(ts, WRITE_LOCK); } afs_SortServers(tc->cellHosts, AFS_MAXCELLHOSTS); /* randomize servers */ /* New cell: Build and add to LRU cell queue. */ if (newc) { struct cell_name *cn; cn = afs_cellname_lookup_name(acellName); if (!cn) cn = afs_cellname_new(acellName, 0); tc->cnamep = cn; tc->cellNum = cn->cellnum; tc->cellIndex = afs_cellindex++; afs_stats_cmperf.numCellsVisible++; QAdd(&CellLRU, &tc->lruq); } ReleaseWriteLock(&tc->lock); ReleaseWriteLock(&afs_xcell); afs_PutCell(tc, 0); if (!(aflags & CHush)) afs_DynrootInvalidate(); return 0; bad: if (newc) { afs_osi_FreeStr(tc->cellName); afs_osi_Free(tc, sizeof(struct cell)); } ReleaseWriteLock(&tc->lock); ReleaseWriteLock(&afs_xcell); return code; }
/*! * Handles all the reconnection details: * - Get all the details about the vnode: name, fid, and parent dir fid. * - Send data to server. * - Handle errors. * - Reorder vhash and dcaches in their hashes, using the newly acquired fid. */ int afs_ProcessOpCreate(struct vcache *avc, struct vrequest *areq, afs_ucred_t *acred) { char *tname = NULL, *ttargetName = NULL; struct AFSStoreStatus InStatus; struct AFSFetchStatus OutFidStatus, OutDirStatus; struct VenusFid pdir_fid, newFid; struct AFSCallBack CallBack; struct AFSVolSync tsync; struct vcache *tdp = NULL, *tvc = NULL; struct dcache *tdc = NULL; struct afs_conn *tc; struct rx_connection *rxconn; afs_int32 hash, new_hash, index; afs_size_t tlen; int code, op = 0; XSTATS_DECLS; tname = afs_osi_Alloc(AFSNAMEMAX); if (!tname) return ENOMEM; code = afs_GetParentVCache(avc, 0, &pdir_fid, tname, &tdp); if (code) goto end; /* This data may also be in linkData, but then we have to deal with * the joy of terminating NULLs and . and file modes. So just get * it from the dcache where it won't have been fiddled with. */ if (vType(avc) == VLNK) { afs_size_t offset; struct dcache *tdc; struct osi_file *tfile; tdc = afs_GetDCache(avc, 0, areq, &offset, &tlen, 0); if (!tdc) { code = ENOENT; goto end; } if (tlen > 1024) { afs_PutDCache(tdc); code = EFAULT; goto end; } tlen++; /* space for NULL */ ttargetName = afs_osi_Alloc(tlen); if (!ttargetName) { afs_PutDCache(tdc); return ENOMEM; } ObtainReadLock(&tdc->lock); tfile = afs_CFileOpen(&tdc->f.inode); code = afs_CFileRead(tfile, 0, ttargetName, tlen); ttargetName[tlen-1] = '\0'; afs_CFileClose(tfile); ReleaseReadLock(&tdc->lock); afs_PutDCache(tdc); } /* Set status. */ InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP; InStatus.ClientModTime = avc->f.m.Date; InStatus.Owner = avc->f.m.Owner; InStatus.Group = (afs_int32) afs_cr_gid(acred); /* Only care about protection bits. */ InStatus.UnixModeBits = avc->f.m.Mode & 0xffff; do { tc = afs_Conn(&tdp->f.fid, areq, SHARED_LOCK, &rxconn); if (tc) { switch (vType(avc)) { case VREG: /* Make file on server. */ op = AFS_STATS_FS_RPCIDX_CREATEFILE; XSTATS_START_TIME(op); RX_AFS_GUNLOCK(); code = RXAFS_CreateFile(tc->id, (struct AFSFid *)&tdp->f.fid.Fid, tname, &InStatus, (struct AFSFid *) &newFid.Fid, &OutFidStatus, &OutDirStatus, &CallBack, &tsync); RX_AFS_GLOCK(); XSTATS_END_TIME; break; case VDIR: /* Make dir on server. */ op = AFS_STATS_FS_RPCIDX_MAKEDIR; XSTATS_START_TIME(op); RX_AFS_GUNLOCK(); code = RXAFS_MakeDir(rxconn, (struct AFSFid *) &tdp->f.fid.Fid, tname, &InStatus, (struct AFSFid *) &newFid.Fid, &OutFidStatus, &OutDirStatus, &CallBack, &tsync); RX_AFS_GLOCK(); XSTATS_END_TIME; break; case VLNK: /* Make symlink on server. */ op = AFS_STATS_FS_RPCIDX_SYMLINK; XSTATS_START_TIME(op); RX_AFS_GUNLOCK(); code = RXAFS_Symlink(rxconn, (struct AFSFid *) &tdp->f.fid.Fid, tname, ttargetName, &InStatus, (struct AFSFid *) &newFid.Fid, &OutFidStatus, &OutDirStatus, &tsync); RX_AFS_GLOCK(); XSTATS_END_TIME; break; default: op = AFS_STATS_FS_RPCIDX_CREATEFILE; code = 1; break; } } else code = -1; } while (afs_Analyze(tc, rxconn, code, &tdp->f.fid, areq, op, SHARED_LOCK, NULL)); /* TODO: Handle errors. */ if (code) { /* printf("afs_ProcessOpCreate: error while creating vnode on server, code=%d .\n", code); */ goto end; } /* The rpc doesn't set the cell number. */ newFid.Cell = avc->f.fid.Cell; /* * Change the fid in the dir entry. */ /* Seek the dir's dcache. */ tdc = afs_FindDCacheByFid(&tdp->f.fid); if (tdc) { /* And now change the fid in the parent dir entry. */ afs_dir_ChangeFid(tdc, tname, &avc->f.fid.Fid.Vnode, &newFid.Fid.Vnode); afs_PutDCache(tdc); } if (vType(avc) == VDIR) { /* Change fid in the dir for the "." entry. ".." has alredy been * handled by afs_FixChildrenFids when processing the parent dir. */ tdc = afs_FindDCacheByFid(&avc->f.fid); if (tdc) { afs_dir_ChangeFid(tdc, ".", &avc->f.fid.Fid.Vnode, &newFid.Fid.Vnode); if (avc->f.m.LinkCount >= 2) /* For non empty dirs, fix children's parentVnode and * parentUnique reference. */ afs_FixChildrenFids(&avc->f.fid, &newFid); afs_PutDCache(tdc); } } /* Recompute hash chain positions for vnode and dcaches. * Then change to the new FID. */ /* The vcache goes first. */ ObtainWriteLock(&afs_xvcache, 735); /* Old fid hash. */ hash = VCHash(&avc->f.fid); /* New fid hash. */ new_hash = VCHash(&newFid); /* Remove hash from old position. */ /* XXX: not checking array element contents. It shouldn't be empty. * If it oopses, then something else might be wrong. */ if (afs_vhashT[hash] == avc) { /* First in hash chain (might be the only one). */ afs_vhashT[hash] = avc->hnext; } else { /* More elements in hash chain. */ for (tvc = afs_vhashT[hash]; tvc; tvc = tvc->hnext) { if (tvc->hnext == avc) { tvc->hnext = avc->hnext; break; } } } /* if (!afs_vhashT[i]->hnext) */ QRemove(&avc->vhashq); /* Insert hash in new position. */ avc->hnext = afs_vhashT[new_hash]; afs_vhashT[new_hash] = avc; QAdd(&afs_vhashTV[VCHashV(&newFid)], &avc->vhashq); ReleaseWriteLock(&afs_xvcache); /* Do the same thing for all dcaches. */ hash = DVHash(&avc->f.fid); ObtainWriteLock(&afs_xdcache, 743); for (index = afs_dvhashTbl[hash]; index != NULLIDX; index = hash) { hash = afs_dvnextTbl[index]; tdc = afs_GetValidDSlot(index); ReleaseReadLock(&tdc->tlock); if (afs_indexUnique[index] == avc->f.fid.Fid.Unique) { if (!FidCmp(&tdc->f.fid, &avc->f.fid)) { /* Safer but slower. */ afs_HashOutDCache(tdc, 0); /* Put dcache in new positions in the dchash and dvhash. */ new_hash = DCHash(&newFid, tdc->f.chunk); afs_dcnextTbl[tdc->index] = afs_dchashTbl[new_hash]; afs_dchashTbl[new_hash] = tdc->index; new_hash = DVHash(&newFid); afs_dvnextTbl[tdc->index] = afs_dvhashTbl[new_hash]; afs_dvhashTbl[new_hash] = tdc->index; afs_indexUnique[tdc->index] = newFid.Fid.Unique; memcpy(&tdc->f.fid, &newFid, sizeof(struct VenusFid)); } /* if fid match */ } /* if uniquifier match */ if (tdc) afs_PutDCache(tdc); } /* for all dcaches in this hash bucket */ ReleaseWriteLock(&afs_xdcache); /* Now we can set the new fid. */ memcpy(&avc->f.fid, &newFid, sizeof(struct VenusFid)); end: if (tdp) afs_PutVCache(tdp); afs_osi_Free(tname, AFSNAMEMAX); if (ttargetName) afs_osi_Free(ttargetName, tlen); return code; }
/*! * All files that have been dirty before disconnection are going to * be replayed back to the server. * * \param areq Request from the user. * \param acred User credentials. * * \return If all files synchronized succesfully, return 0, otherwise * return error code * * \note For now, it's the request from the PDiscon pioctl. * */ int afs_ResyncDisconFiles(struct vrequest *areq, afs_ucred_t *acred) { struct afs_conn *tc; struct rx_connection *rxconn; struct vcache *tvc; struct AFSFetchStatus fstat; struct AFSCallBack callback; struct AFSVolSync tsync; int code = 0; afs_int32 start = 0; XSTATS_DECLS; /*AFS_STATCNT(afs_ResyncDisconFiles);*/ ObtainWriteLock(&afs_disconDirtyLock, 707); while (!QEmpty(&afs_disconDirty)) { tvc = QEntry(QPrev(&afs_disconDirty), struct vcache, dirtyq); /* Can't lock tvc whilst holding the discon dirty lock */ ReleaseWriteLock(&afs_disconDirtyLock); /* Get local write lock. */ ObtainWriteLock(&tvc->lock, 705); if (tvc->f.ddirty_flags & VDisconRemove) { /* Delete the file on the server and just move on * to the next file. After all, it has been deleted * we can't replay any other operation it. */ code = afs_ProcessOpRemove(tvc, areq); goto next_file; } else if (tvc->f.ddirty_flags & VDisconCreate) { /* For newly created files, we don't need a server lock. */ code = afs_ProcessOpCreate(tvc, areq, acred); if (code) goto next_file; tvc->f.ddirty_flags &= ~VDisconCreate; tvc->f.ddirty_flags |= VDisconCreated; } #if 0 /* Get server write lock. */ do { tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn); if (tc) { XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETLOCK); RX_AFS_GUNLOCK(); code = RXAFS_SetLock(rxconn, (struct AFSFid *)&tvc->f.fid.Fid, LockWrite, &tsync); RX_AFS_GLOCK(); XSTATS_END_TIME; } else code = -1; } while (afs_Analyze(tc, rxconn, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETLOCK, SHARED_LOCK, NULL)); if (code) goto next_file; #endif if (tvc->f.ddirty_flags & VDisconRename) { /* If we're renaming the file, do so now */ code = afs_ProcessOpRename(tvc, areq); if (code) goto unlock_srv_file; } /* Issue a FetchStatus to get info about DV and callbacks. */ do { tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn); if (tc) { tvc->callback = tc->srvr->server; start = osi_Time(); XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS); RX_AFS_GUNLOCK(); code = RXAFS_FetchStatus(rxconn, (struct AFSFid *)&tvc->f.fid.Fid, &fstat, &callback, &tsync); RX_AFS_GLOCK(); XSTATS_END_TIME; } else code = -1; } while (afs_Analyze(tc, rxconn, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHSTATUS, SHARED_LOCK, NULL)); if (code) { goto unlock_srv_file; } if ((dv_match(tvc, fstat) && (tvc->f.m.Date == fstat.ServerModTime)) || (afs_ConflictPolicy == CLIENT_WINS) || (tvc->f.ddirty_flags & VDisconCreated)) { /* * Send changes to the server if there's data version match, or * client wins policy has been selected or file has been created * but doesn't have it's the contents on to the server yet. */ /* * XXX: Checking server attr changes by timestamp might not the * most elegant solution, but it's the most viable one that we could find. */ afs_UpdateStatus(tvc, &tvc->f.fid, areq, &fstat, &callback, start); code = afs_SendChanges(tvc, areq); } else if (afs_ConflictPolicy == SERVER_WINS) { /* DV mismatch, apply collision resolution policy. */ /* Discard this files chunks and remove from current dir. */ afs_ResetVCache(tvc, acred, 0); tvc->f.truncPos = AFS_NOTRUNC; } else { /* printf("afs_ResyncDisconFiles: no resolution policy selected.\n"); */ } /* if DV match or client wins policy */ unlock_srv_file: /* Release server write lock. */ #if 0 do { tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn); if (tc) { XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK); RX_AFS_GUNLOCK(); ucode = RXAFS_ReleaseLock(rxconn, (struct AFSFid *) &tvc->f.fid.Fid, &tsync); RX_AFS_GLOCK(); XSTATS_END_TIME; } else ucode = -1; } while (afs_Analyze(tc, rxconn, ucode, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RELEASELOCK, SHARED_LOCK, NULL)); #endif next_file: ObtainWriteLock(&afs_disconDirtyLock, 710); if (code == 0) { /* Replayed successfully - pull the vcache from the * disconnected list */ tvc->f.ddirty_flags = 0; QRemove(&tvc->dirtyq); afs_PutVCache(tvc); } else { if (code == EAGAIN) { /* Operation was deferred. Pull it from the current place in * the list, and stick it at the end again */ QRemove(&tvc->dirtyq); QAdd(&afs_disconDirty, &tvc->dirtyq); } else { /* Failed - keep state as is, and let the user know we died */ ReleaseWriteLock(&tvc->lock); break; } } /* Release local write lock. */ ReleaseWriteLock(&tvc->lock); } /* while (tvc) */ if (code) { ReleaseWriteLock(&afs_disconDirtyLock); return code; } /* Dispose of all of the shadow directories */ afs_DisconDiscardAllShadows(0, acred); ReleaseWriteLock(&afs_disconDirtyLock); return code; }
void afs_CheckCallbacks(unsigned int secs) { struct vcache *tvc; register struct afs_q *tq; struct afs_q *uq; afs_uint32 now; struct volume *tvp; register int safety; ObtainWriteLock(&afs_xcbhash, 85); /* pretty likely I'm going to remove something */ now = osi_Time(); for (safety = 0, tq = cbHashT[base].head.prev; (safety <= CBQ_LIMIT) && (tq != &(cbHashT[base].head)); tq = uq, safety++) { uq = QPrev(tq); tvc = CBQTOV(tq); if (tvc->cbExpires < now + secs) { /* race #1 here */ /* Get the volume, and if its callback expiration time is more than secs * seconds into the future, update this vcache entry and requeue it below */ if ((tvc->f.states & CRO) && (tvp = afs_FindVolume(&(tvc->f.fid), READ_LOCK))) { if (tvp->expireTime > now + secs) { tvc->cbExpires = tvp->expireTime; /* XXX race here */ } else { int i; for (i = 0; i < MAXHOSTS && tvp->serverHost[i]; i++) { if (!(tvp->serverHost[i]->flags & SRVR_ISDOWN)) { /* What about locking xvcache or vrefcount++ or * write locking tvc? */ QRemove(tq); tvc->f.states &= ~(CStatd | CMValid | CUnique); if (!(tvc->f.states & (CVInit|CVFlushed)) && (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))) osi_dnlc_purgedp(tvc); tvc->dchint = NULL; /*invalidate em */ afs_ResetVolumeInfo(tvp); break; } } } afs_PutVolume(tvp, READ_LOCK); } else { /* Do I need to worry about things like execsorwriters? * What about locking xvcache or vrefcount++ or write locking tvc? */ QRemove(tq); tvc->f.states &= ~(CStatd | CMValid | CUnique); if (!(tvc->f.states & (CVInit|CVFlushed)) && (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))) osi_dnlc_purgedp(tvc); } } if ((tvc->cbExpires > basetime) && CBHash(tvc->cbExpires - basetime)) { /* it's been renewed on us. Have to be careful not to put it back * into this slot, or we may never get out of here. */ int slot; slot = (CBHash(tvc->cbExpires - basetime) + base) % CBHTSIZE; if (slot != base) { if (QPrev(tq)) QRemove(&(tvc->callsort)); QAdd(&(cbHashT[slot].head), &(tvc->callsort)); /* XXX remember to update volume expiration time */ /* -- not needed for correctness, though */ } } } if (safety > CBQ_LIMIT) { afs_stats_cmperf.cbloops++; if (afs_paniconwarn) osi_Panic("CheckCallbacks"); afs_warn ("AFS Internal Error (minor): please contact AFS Product Support.\n"); ReleaseWriteLock(&afs_xcbhash); afs_FlushCBs(); return; } else ReleaseWriteLock(&afs_xcbhash); /* XXX future optimization: if this item has been recently accessed, queue up a stat for it. { struct dcache * adc; ObtainReadLock(&afs_xdcache); if ((adc = tvc->quick.dc) && (adc->stamp == tvc->quick.stamp) && (afs_indexTimes[adc->index] > afs_indexCounter - 20)) { queue up the stat request } ReleaseReadLock(&afs_xdcache); } */ return; } /* afs_CheckCallback */