Beispiel #1
0
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;
}
Beispiel #2
0
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 */
Beispiel #3
0
/* 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;
}
Beispiel #4
0
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);
}
Beispiel #5
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;
}
Beispiel #6
0
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);
    }
}