int afscp_GetStatus(const struct afscp_venusfid *fid, struct AFSFetchStatus *s) { struct afscp_volume *v; struct afscp_server *server; struct AFSCallBack cb; struct AFSVolSync vs; struct AFSFid tf = fid->fid; struct afscp_statent *stored, key; void *cached; int code, i, j; time_t now; v = afscp_VolumeById(fid->cell, fid->fid.Volume); if (v == NULL) { return -1; } memset(&key, 0, sizeof(key)); memcpy(&key.me, fid, sizeof(*fid)); cached = tfind(&key, &v->statcache, statcompare); if (cached != NULL) { stored = *(struct afscp_statent **)cached; pthread_mutex_lock(&(stored->mtx)); memmove(s, &stored->status, sizeof(*s)); afs_dprintf(("Stat %u.%lu.%lu.%lu returning cached result\n", fid->cell->id, fid->fid.Volume, fid->fid.Vnode, fid->fid.Unique)); if (stored->nwaiters) pthread_cond_broadcast(&(stored->cv)); pthread_mutex_unlock(&(stored->mtx)); return 0; } code = ENOENT; for (i = 0; i < v->nservers; i++) { server = afscp_ServerByIndex(v->servers[i]); if (server && server->naddrs > 0) { for (j = 0; j < server->naddrs; j++) { time(&now); code = RXAFS_FetchStatus(server->conns[j], &tf, s, &cb, &vs); if (code == 0) { afscp_AddCallBack(server, &fid->fid, s, &cb, now); /* calls _StatStuff */ afs_dprintf(("Stat %d.%lu.%lu.%lu" " ok: type %ld size %ld\n", fid->cell->id, afs_printable_uint32_lu(fid->fid.Volume), afs_printable_uint32_lu(fid->fid.Vnode), afs_printable_uint32_lu(fid->fid.Unique), afs_printable_int32_ld(s->FileType), afs_printable_int32_ld(s->Length))); return 0; } } } } afscp_errno = code; return -1; }
afs_int32 rpc_test_afs_fetch_status(rpc_test_request_ctx *ctx, AFSFid *fid, AFSFetchStatus *outstatus) { struct AFSVolSync tsync; struct AFSCallBack tcb; afs_int32 code = 0; RXCALL_WITH_SOCK(code, ctx, (RXAFS_FetchStatus(ctx->conn, fid, outstatus, &tcb, &tsync))); return (code); } /* rpc_test_afs_fetch_status */
/* this is not yet 64-bit clean */ ssize_t afscp_PWrite(const struct afscp_venusfid * fid, const void *buffer, size_t count, off_t offset) { struct AFSFetchStatus fst; struct AFSStoreStatus sst; struct AFSVolSync vs; struct AFSCallBack cb; struct AFSFid tf = fid->fid; struct afscp_volume *vol; struct afscp_server *server; struct rx_call *c = NULL; int code, code2 = 0; int i, j, bytes, totalbytes = 0; int bytesremaining; const char *p; off_t filesize; time_t now; vol = afscp_VolumeById(fid->cell, fid->fid.Volume); if (vol == NULL) { afscp_errno = ENOENT; return -1; } if (vol->voltype != RWVOL) { afscp_errno = EROFS; return -1; } code = ENOENT; for (i = 0; i < vol->nservers; i++) { server = afscp_ServerByIndex(vol->servers[i]); if (server && server->naddrs > 0) { for (j = 0; j < server->naddrs; j++) { code = RXAFS_FetchStatus(server->conns[j], &tf, &fst, &cb, &vs); if (code != 0) continue; sst.Mask = AFS_SETMODTIME; time(&now); sst.ClientModTime = now; filesize = fst.Length; if (offset + count > filesize) filesize = offset + count; c = rx_NewCall(server->conns[j]); if (c != 0) { p = buffer; code = StartRXAFS_StoreData(c, &tf, &sst, offset, count, filesize); if (code != 0) { code = rx_EndCall(c, code); continue; } /* * seems to write file length to beginning of file -- why? */ /* * bytesremaining = htonl(count); * bytes = rx_Write(c, (char *)&bytesremaining, * sizeof(afs_int32)); * if (bytes != sizeof(afs_int32)) { * code = rx_EndCall(c, bytes); * continue; * } */ bytesremaining = count; totalbytes = 0; while (bytesremaining > 0) { bytes = rx_Write(c, (char *)p, bytesremaining); if (bytes <= 0) break; p += bytes; totalbytes += bytes; bytesremaining -= bytes; } if (bytesremaining == 0) { code2 = EndRXAFS_StoreData(c, &fst, &vs); } code = rx_EndCall(c, code2); } if (code == 0) { return totalbytes; } } } } afscp_errno = code; return -1; }
int main(int argc, char **argv) { char scell[MAXCELLCHARS], dcell[MAXCELLCHARS]; afs_uint32 ssrv, dsrv; char *databuffer, *srcf = NULL, *destd = NULL, *destf = NULL, *destpath = NULL; struct stat statbuf; struct AFSStoreStatus sst; struct AFSFetchStatus fst, dfst; struct AFSVolSync vs; struct AFSCallBack scb, dcb; struct AFSFid sf, dd, df; int filesz = 0; int ch, blksize, bytesremaining, bytes; struct timeval start, finish; struct timezone tz; struct rx_securityClass *ssc = 0, *dsc = 0; int sscindex, dscindex; struct rx_connection *sconn = NULL, *dconn = NULL; struct rx_call *scall = NULL, *dcall = NULL; int code = 0, fetchcode, storecode, printcallerrs = 0; int slcl = 0, dlcl = 0, unlock = 0; int sfd = 0, dfd = 0, unauth = 0; struct AFSCBFids theFids; struct AFSCBs theCBs; blksize = 8 * 1024; while ((ch = getopt(argc, argv, "iouUb:")) != -1) { switch (ch) { case 'b': blksize = atoi(optarg); break; case 'i': slcl = 1; break; case 'o': dlcl = 1; break; case 'u': unauth = 1; break; case 'U': unlock = 1; break; default: printf("Unknown option '%c'\n", ch); exit(1); } } if (argc - optind + unlock < 2) { fprintf(stderr, "Usage: afscp [-i|-o]] [-b xfersz] [-u] [-U] source [dest]\n"); fprintf(stderr, " -b Set block size\n"); fprintf(stderr, " -i Source is local (copy into AFS)\n"); fprintf(stderr, " -o Dest is local (copy out of AFS)\n"); fprintf(stderr, " -u Run unauthenticated\n"); fprintf(stderr, " -U Send an unlock request for source. (dest path not required)\n"); fprintf(stderr, "source and dest can be paths or specified as:\n"); fprintf(stderr, " @afs:cellname:servername:volume:vnode:uniq\n"); exit(1); } srcf = argv[optind++]; if (!unlock) { destpath = argv[optind++]; destd = strdup(destpath); if (!destd) { perror("strdup"); exit(1); } if ((destf = strrchr(destd, '/'))) { *destf++ = 0; } else { destf = destd; destd = "."; } } else if (slcl) { fprintf(stderr, "-i and -U cannot be used together\n"); } if (!slcl && statfile(srcf, scell, &ssrv, &sf)) { fprintf(stderr, "Cannot get attributes of %s\n", srcf); exit(1); } if (!unlock && !dlcl && statfile(destd, dcell, &dsrv, &dd)) { fprintf(stderr, "Cannot get attributes of %s\n", destd); exit(1); } if ((databuffer = malloc(blksize)) == NULL) { perror("malloc"); exit(1); } if (do_rx_Init()) exit(1); if (start_cb_server()) { printf("Cannot start callback service\n"); goto Fail_rx; } if (!slcl) { sscindex = scindex_RXKAD; if (unauth || (ssc = get_sc(scell)) == NULL) { ssc = rxnull_NewClientSecurityObject(); sscindex = scindex_NULL; /*printf("Cannot get authentication for cell %s; running unauthenticated\n", scell); */ } sscindex = scindex_NULL; if ((sconn = rx_NewConnection(ssrv, htons(AFSCONF_FILEPORT), 1, ssc, sscindex)) == NULL) { struct in_addr s; s.s_addr = ssrv; printf("Cannot initialize rx connection to source server (%s)\n", inet_ntoa(s)); goto Fail_sc; } } if (!dlcl && !unlock) { if (!slcl && ssrv == dsrv) { dconn = sconn; dsc = NULL; } else { if (slcl || strcmp(scell, dcell)) { dscindex = scindex_RXKAD; if (unauth || (dsc = get_sc(dcell)) == NULL) { dsc = rxnull_NewClientSecurityObject(); dscindex = scindex_NULL; /*printf("Cannot get authentication for cell %s; running unauthenticated\n", dcell); */ } dscindex = scindex_NULL; } else { dsc = ssc; dscindex = sscindex; } if ((dconn = rx_NewConnection(dsrv, htons(AFSCONF_FILEPORT), 1, dsc, dscindex)) == NULL) { struct in_addr s; s.s_addr = dsrv; printf ("Cannot initialize rx connection to dest server (%s)\n", inet_ntoa(s)); goto Fail_sconn; } } } memset(&sst, 0, sizeof(struct AFSStoreStatus)); if (dlcl && !unlock) { dfd = open(destpath, O_RDWR | O_CREAT | O_EXCL, 0666); if (dfd < 0 && errno == EEXIST) { printf("%s already exists, overwriting\n", destpath); dfd = open(destpath, O_RDWR | O_TRUNC, 0666); if (dfd < 0) { fprintf(stderr, "Cannot open %s (%s)\n", destpath, afs_error_message(errno)); goto Fail_dconn; } } else if (dfd < 0) { fprintf(stderr, "Cannot open %s (%s)\n", destpath, afs_error_message(errno)); goto Fail_dconn; } } else if (!unlock) { if ((code = RXAFS_CreateFile(dconn, &dd, destf, &sst, &df, &fst, &dfst, &dcb, &vs))) { if (code == EEXIST) { printf("%s already exits, overwriting\n", destpath); if (statfile(destpath, dcell, &dsrv, &df)) fprintf(stderr, "Cannot get attributes of %s\n", destpath); else code = 0; } else { printf("Cannot create %s (%s)\n", destpath, afs_error_message(code)); if (code) goto Fail_dconn; } } } if (slcl) { sfd = open(srcf, O_RDONLY, 0); if (sfd < 0) { fprintf(stderr, "Cannot open %s (%s)\n", srcf, afs_error_message(errno)); goto Fail_dconn; } if (fstat(sfd, &statbuf) < 0) { fprintf(stderr, "Cannot stat %s (%s)\n", srcf, afs_error_message(errno)); close(sfd); goto Fail_dconn; } } else { if ((code = RXAFS_FetchStatus(sconn, &sf, &fst, &scb, &vs))) { printf("Cannot fetchstatus of %d.%d (%s)\n", sf.Volume, sf.Vnode, afs_error_message(code)); goto Fail_dconn; } } if (slcl) { filesz = statbuf.st_size; } else { filesz = fst.Length; } printcallerrs = 0; fetchcode = 0; storecode = 0; if (!slcl && !unlock) scall = rx_NewCall(sconn); if (!dlcl && !unlock) dcall = rx_NewCall(dconn); gettimeofday(&start, &tz); if (unlock) { if (fst.lockCount) { printf("Sending 1 unlock for %s (%d locks)\n", srcf, fst.lockCount); if ((code = RXAFS_ReleaseLock(sconn, &sf, &vs))) { printf("Unable to unlock %s (%s)\n", srcf, afs_error_message(code)); } } else { printf("No locks for %s\n", srcf); } fetchcode = code; goto Finish; } if (!slcl) { if ((code = StartRXAFS_FetchData(scall, &sf, 0, filesz))) { printf("Unable to fetch data from %s (%s)\n", srcf, afs_error_message(code)); goto Fail_call; } } if (!dlcl) { if (slcl) { sst.Mask = AFS_SETMODTIME | AFS_SETMODE; sst.ClientModTime = statbuf.st_mtime; sst.UnixModeBits = statbuf.st_mode & ~(S_IFMT | S_ISUID | S_ISGID); } else { sst.Mask = AFS_SETMODTIME | AFS_SETMODE; sst.ClientModTime = fst.ClientModTime; sst.UnixModeBits = fst.UnixModeBits & ~(S_IFMT | S_ISUID | S_ISGID); } if ((code = StartRXAFS_StoreData(dcall, &df, &sst, 0, filesz, filesz))) { printf("Unable to store data to %s (%s)\n", destpath, afs_error_message(code)); goto Fail_call; } } if (slcl) { bytesremaining = statbuf.st_size; } else { rx_Read(scall, (char *)&bytesremaining, sizeof(afs_int32)); bytesremaining = ntohl(bytesremaining); } while (bytesremaining > 0) { /*printf("%d bytes remaining\n",bytesremaining); */ if (slcl) { if ((bytes = read(sfd, databuffer, min(blksize, bytesremaining))) <= 0) { fetchcode = errno; break; } } else { if ((bytes = rx_Read(scall, databuffer, min(blksize, bytesremaining))) <= 0) break; } if (dlcl) { if (write(dfd, databuffer, bytes) != bytes) { storecode = errno; break; } } else { if (rx_Write(dcall, databuffer, bytes) != bytes) break; } bytesremaining -= bytes; /*printf("%d bytes copied\n",bytes); */ } if (bytesremaining > 0) { printf("Some network error occured while copying data\n"); goto Fail_call; } if (!slcl) fetchcode = EndRXAFS_FetchData(scall, &fst, &scb, &vs); if (!dlcl) storecode = EndRXAFS_StoreData(dcall, &fst, &vs); printcallerrs = 1; Fail_call: if (slcl) { if (close(sfd) && !fetchcode) fetchcode = errno; } else { fetchcode = rx_EndCall(scall, fetchcode); } if (fetchcode && printcallerrs) printf("Error returned from fetch: %s\n", afs_error_message(fetchcode)); if (dlcl) { if (close(dfd) && !storecode) storecode = errno; } else if (!unlock) { storecode = rx_EndCall(dcall, storecode); } if (storecode && printcallerrs) printf("Error returned from store: %s\n", afs_error_message(storecode)); Finish: gettimeofday(&finish, &tz); if (!slcl) { theFids.AFSCBFids_len = 1; theFids.AFSCBFids_val = &sf; theCBs.AFSCBs_len = 1; theCBs.AFSCBs_val = &scb; scb.CallBackType = CB_DROPPED; if ((code = RXAFS_GiveUpCallBacks(sconn, &theFids, &theCBs))) printf("Could not give up source callback: %s\n", afs_error_message(code)); } if (!dlcl) { theFids.AFSCBFids_len = 1; theFids.AFSCBFids_val = &df; theCBs.AFSCBs_len = 1; theCBs.AFSCBs_val = &dcb; dcb.CallBackType = CB_DROPPED; if ((code = RXAFS_GiveUpCallBacks(dconn, &theFids, &theCBs))) printf("Could not give up target callback: %s\n", afs_error_message(code)); } if (code == 0) code = storecode; if (code == 0) code = fetchcode; Fail_dconn: if (!dlcl && !unlock && (slcl || dconn != sconn)) rx_DestroyConnection(dconn); Fail_sconn: if (!slcl) rx_DestroyConnection(sconn); Fail_sc: if (dsc && dsc != ssc) RXS_Close(dsc); if (ssc) RXS_Close(ssc); Fail_rx: rx_Finalize(); free(databuffer); if (printcallerrs && !unlock) { double rate, size, time; if (finish.tv_sec == start.tv_sec) { printf("Copied %d bytes in %d microseconds\n", filesz, (int)(finish.tv_usec - start.tv_usec)); } else { printf("Copied %d bytes in %d seconds\n", filesz, (int)(finish.tv_sec - start.tv_sec)); } size = filesz / 1024.0; time = finish.tv_sec - start.tv_sec + (finish.tv_usec - start.tv_usec) / 1e+06; rate = size / time; printf("Transfer rate %g Kbytes/sec\n", rate); } exit(code != 0); }
/*! * 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; }
int afs_lockctl(struct vcache * avc, struct AFS_FLOCK * af, int acmd, afs_ucred_t * acred) #endif { struct vrequest treq; afs_int32 code; struct afs_fakestat_state fakestate; AFS_STATCNT(afs_lockctl); if ((code = afs_InitReq(&treq, acred))) return code; afs_InitFakeStat(&fakestate); AFS_DISCON_LOCK(); code = afs_EvalFakeStat(&avc, &fakestate, &treq); if (code) { goto done; } #if defined(AFS_SGI_ENV) if ((acmd == F_GETLK) || (acmd == F_RGETLK)) { #else if (acmd == F_GETLK) { #endif if (af->l_type == F_UNLCK) { code = 0; goto done; } code = HandleGetLock(avc, af, &treq, clid); code = afs_CheckCode(code, &treq, 2); /* defeat buggy AIX optimz */ goto done; } else if ((acmd == F_SETLK) || (acmd == F_SETLKW) #if defined(AFS_SGI_ENV) || (acmd == F_RSETLK) || (acmd == F_RSETLKW)) { #else ) { #endif if ((avc->f.states & CRO)) { /* for RO volumes, don't do anything for locks; the fileserver doesn't * even track them. A write lock should not be possible, though. */ if (af->l_type == F_WRLCK) { code = EBADF; } else { code = 0; } goto done; } /* Java VMs ask for l_len=(long)-1 regardless of OS/CPU */ if ((sizeof(af->l_len) == 8) && (af->l_len == 0x7fffffffffffffffLL)) af->l_len = 0; /* next line makes byte range locks always succeed, * even when they should block */ if (af->l_whence != 0 || af->l_start != 0 || af->l_len != 0) { DoLockWarning(acred); code = 0; goto done; } /* otherwise we can turn this into a whole-file flock */ if (af->l_type == F_RDLCK) code = LOCK_SH; else if (af->l_type == F_WRLCK) code = LOCK_EX; else if (af->l_type == F_UNLCK) code = LOCK_UN; else { code = EINVAL; /* unknown lock type */ goto done; } if (((acmd == F_SETLK) #if defined(AFS_SGI_ENV) || (acmd == F_RSETLK) #endif ) && code != LOCK_UN) code |= LOCK_NB; /* non-blocking, s.v.p. */ #if defined(AFS_DARWIN_ENV) code = HandleFlock(avc, code, &treq, clid, 0 /*!onlymine */ ); #elif defined(AFS_SGI_ENV) AFS_RWLOCK((vnode_t *) avc, VRWLOCK_WRITE); code = HandleFlock(avc, code, &treq, clid, 0 /*!onlymine */ ); AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE); #else code = HandleFlock(avc, code, &treq, 0, 0 /*!onlymine */ ); #endif code = afs_CheckCode(code, &treq, 3); /* defeat AIX -O bug */ goto done; } code = EINVAL; done: afs_PutFakeStat(&fakestate); AFS_DISCON_UNLOCK(); return code; } /* * Get a description of the first lock which would * block the lock specified. If the specified lock * would succeed, fill in the lock structure with 'F_UNLCK'. * * To do that, we have to ask the server for the lock * count if: * 1. The file is not locked by this machine. * 2. Asking for write lock, and only the current * PID has the file read locked. */ static int HandleGetLock(struct vcache *avc, struct AFS_FLOCK *af, struct vrequest *areq, int clid) { afs_int32 code; struct AFS_FLOCK flock; lockIdSet(&flock, NULL, clid); ObtainWriteLock(&avc->lock, 122); if (avc->flockCount == 0) { /* * We don't know ourselves, so ask the server. Unfortunately, we * don't know the pid. Not even the server knows the pid. Besides, * the process with the lock is on another machine */ code = GetFlockCount(avc, areq); if (code == 0 || (af->l_type == F_RDLCK && code > 0)) { af->l_type = F_UNLCK; goto unlck_leave; } if (code > 0) af->l_type = F_RDLCK; else af->l_type = F_WRLCK; af->l_pid = 0; #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = 0; #endif goto done; } if (af->l_type == F_RDLCK) { /* * We want a read lock. If there are only * read locks, or we are the one with the * write lock, say it is unlocked. */ if (avc->flockCount > 0 || /* only read locks */ !lockIdcmp2(&flock, avc, NULL, 1, clid)) { af->l_type = F_UNLCK; goto unlck_leave; } /* one write lock, but who? */ af->l_type = F_WRLCK; /* not us, so lock would block */ if (avc->slocks) { /* we know who, so tell */ af->l_pid = avc->slocks->pid; #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = avc->slocks->sysid; #endif } else { af->l_pid = 0; /* XXX can't happen?? */ #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = 0; #endif } goto done; } /* * Ok, we want a write lock. If there is a write lock * already, and it is not this process, we fail. */ if (avc->flockCount < 0) { if (lockIdcmp2(&flock, avc, NULL, 1, clid)) { af->l_type = F_WRLCK; if (avc->slocks) { af->l_pid = avc->slocks->pid; #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = avc->slocks->sysid; #endif } else { af->l_pid = 0; /* XXX can't happen?? */ #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = 0; #endif } goto done; } /* we are the one with the write lock */ af->l_type = F_UNLCK; goto unlck_leave; } /* * Want a write lock, and we know there are read locks. * If there is more than one, or it isn't us, we cannot lock. */ if ((avc->flockCount > 1) || lockIdcmp2(&flock, avc, NULL, 1, clid)) { struct SimpleLocks *slp; af->l_type = F_RDLCK; af->l_pid = 0; #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = 0; #endif /* find a pid that isn't our own */ for (slp = avc->slocks; slp; slp = slp->next) { if (lockIdcmp2(&flock, NULL, slp, 1, clid)) { af->l_pid = slp->pid; #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = avc->slocks->sysid; #endif break; } } goto done; } /* * Ok, we want a write lock. If there is a write lock * already, and it is not this process, we fail. */ if (avc->flockCount < 0) { if (lockIdcmp2(&flock, avc, NULL, 1, clid)) { af->l_type = F_WRLCK; if (avc->slocks) { af->l_pid = avc->slocks->pid; #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = avc->slocks->sysid; #endif } else { af->l_pid = 0; /* XXX can't happen?? */ #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = 0; #endif } goto done; } /* we are the one with the write lock */ af->l_type = F_UNLCK; goto unlck_leave; } /* * Want a write lock, and we know there are read locks. * If there is more than one, or it isn't us, we cannot lock. */ if ((avc->flockCount > 1) || lockIdcmp2(&flock, avc, NULL, 1, clid)) { struct SimpleLocks *slp; af->l_type = F_RDLCK; af->l_pid = 0; #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = 0; #endif /* find a pid that isn't our own */ for (slp = avc->slocks; slp; slp = slp->next) { if (lockIdcmp2(&flock, NULL, slp, 1, clid)) { af->l_pid = slp->pid; #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = avc->slocks->sysid; #endif break; } } goto done; } /* * Want a write lock, and there is just one read lock, and it * is this process with a read lock. Ask the server if there * are any more processes with the file locked. */ code = GetFlockCount(avc, areq); if (code == 0 || code == 1) { af->l_type = F_UNLCK; goto unlck_leave; } if (code > 0) af->l_type = F_RDLCK; else af->l_type = F_WRLCK; af->l_pid = 0; #if defined(AFS_HAVE_FLOCK_SYSID) af->l_sysid = 0; #endif done: af->l_whence = 0; af->l_start = 0; af->l_len = 0; /* to end of file */ unlck_leave: ReleaseWriteLock(&avc->lock); return 0; } /* Get the 'flock' count from the server. This comes back in a 'spare' * field from a GetStatus RPC. If we have any problems with the RPC, * we lie and say the file is unlocked. If we ask any 'old' fileservers, * the spare field will be a zero, saying the file is unlocked. This is * OK, as a further 'lock' request will do the right thing. */ static int GetFlockCount(struct vcache *avc, struct vrequest *areq) { struct afs_conn *tc; afs_int32 code; struct AFSFetchStatus OutStatus; struct AFSCallBack CallBack; struct AFSVolSync tsync; struct rx_connection *rxconn; int temp; XSTATS_DECLS; temp = areq->flags & O_NONBLOCK; areq->flags |= O_NONBLOCK; /* If we're disconnected, lie and say that we've got no locks. Ick */ if (AFS_IS_DISCONNECTED) return 0; do { tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn); if (tc) { XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS); RX_AFS_GUNLOCK(); code = RXAFS_FetchStatus(rxconn, (struct AFSFid *)&avc->f.fid.Fid, &OutStatus, &CallBack, &tsync); RX_AFS_GLOCK(); XSTATS_END_TIME; } else code = -1; } while (afs_Analyze (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHSTATUS, SHARED_LOCK, NULL)); if (temp) areq->flags &= ~O_NONBLOCK; if (code) { return (0); /* failed, say it is 'unlocked' */ } else { return ((int)OutStatus.lockCount); } }