} /* init_afs_cb */
int
+afscp_FindCallBack(const struct afscp_venusfid *f, const struct afscp_server *server, struct afscp_callback *ret)
+{
+ int i;
+ struct afscp_callback *use = NULL, *cb;
+ time_t now;
+ struct afscp_venusfid fid;
+
+ ret = NULL;
+
+ time(&now);
+ for (i = 0; i < afscp_maxcallbacks; i++) {
+ cb = &allcallbacks[i];
+ if ((f->fid.Volume == cb->fid.Volume) &&
+ (f->fid.Vnode == cb->fid.Vnode) &&
+ (f->fid.Unique == cb->fid.Unique)) {
+ if (server && (cb->server != server))
+ continue;
+ use = cb;
+ break;
+ }
+ }
+ if (!use)
+ return -1;
+
+ if (use->cb.ExpirationTime + use->as_of < now) {
+ if (use->valid) {
+ fid.cell = afscp_CellById(use->server->cell);
+ memcpy(&fid.fid, &use->fid, sizeof(struct AFSFid));
+ _StatInvalidate(&fid);
+ }
+ use->valid = 0;
+ }
+
+ if (use->valid)
+ ret = use;
+ else
+ return -1;
+
+ return 0;
+}
+
+int
afscp_AddCallBack(const struct afscp_server *server,
const struct AFSFid *fid,
const struct AFSFetchStatus *fst,
struct afscp_callback *use = NULL, *newlist;
struct afscp_venusfid f;
time_t now;
-
+
time(&now);
-
+
for (i = 0; i < afscp_maxcallbacks; i++) {
if (allcallbacks[i].cb.ExpirationTime + allcallbacks[i].as_of < now) {
- if (allcallbacks[i].valid) {
- f.cell = afscp_CellById(allcallbacks[i].server->cell);
- memcpy(&f.fid, &allcallbacks[i].fid, sizeof(struct AFSFid));
- _StatInvalidate(&f);
- }
- allcallbacks[i].valid = 0;
-
- }
-
- if (allcallbacks[i].valid == 0)
- use = &allcallbacks[i];
- if ((allcallbacks[i].server == server) &&
- (fid->Volume == allcallbacks[i].fid.Volume) &&
- (fid->Vnode == allcallbacks[i].fid.Vnode) &&
- (fid->Unique == allcallbacks[i].fid.Unique)) {
- use = &allcallbacks[i];
- break;
- }
+ if (allcallbacks[i].valid) {
+ f.cell = afscp_CellById(allcallbacks[i].server->cell);
+ memcpy(&f.fid, &allcallbacks[i].fid, sizeof(struct AFSFid));
+ _StatInvalidate(&f);
+ }
+ allcallbacks[i].valid = 0;
+ }
+
+ if (allcallbacks[i].valid == 0)
+ use = &allcallbacks[i];
+ if ((allcallbacks[i].server == server) &&
+ (fid->Volume == allcallbacks[i].fid.Volume) &&
+ (fid->Vnode == allcallbacks[i].fid.Vnode) &&
+ (fid->Unique == allcallbacks[i].fid.Unique)) {
+ use = &allcallbacks[i];
+ break;
+ }
}
if (use == NULL) {
- if (afscp_maxcallbacks >= afscp_cballoced) {
- if (afscp_cballoced != 0)
- afscp_cballoced = afscp_cballoced * 2;
- else
- afscp_cballoced = 4;
- newlist = realloc(allcallbacks, afscp_cballoced *
+ if (afscp_maxcallbacks >= afscp_cballoced) {
+ if (afscp_cballoced != 0)
+ afscp_cballoced = afscp_cballoced * 2;
+ else
+ afscp_cballoced = 4;
+ newlist = realloc(allcallbacks, afscp_cballoced *
sizeof(struct afscp_callback));
if (newlist == NULL) {
return -1;
return 0;
}
+static void
+_StatCleanup(struct afscp_statent *stored)
+{
+ pthread_cond_destroy(&(stored->cv));
+ pthread_mutex_unlock(&(stored->mtx));
+ pthread_mutex_destroy(&(stored->mtx));
+ free(stored);
+}
+
+int
+afscp_WaitForCallback(const struct afscp_venusfid *fid, int seconds)
+{
+ void **cached;
+ struct afscp_volume *v;
+ struct afscp_statent *stored, key;
+ int code = 0;
+
+ v = afscp_VolumeById(fid->cell, fid->fid.Volume);
+ if (v == NULL) {
+ return -1;
+ }
+ memmove(&key.me, fid, sizeof(*fid));
+
+ cached = tfind(&key, &v->statcache, statcompare);
+ if (cached != NULL) {
+ struct timeval tv;
+ struct timespec ts;
+
+ stored = *(struct afscp_statent **)cached;
+
+ if (seconds) {
+ gettimeofday(&tv, NULL);
+ ts.tv_sec = tv.tv_sec + seconds;
+ ts.tv_nsec = 0;
+ }
+
+ pthread_mutex_lock(&(stored->mtx));
+ stored->nwaiters++;
+ if (seconds)
+ code = pthread_cond_timedwait(&(stored->cv), &(stored->mtx), &ts);
+ else
+ pthread_cond_wait(&(stored->cv), &(stored->mtx));
+ if ((stored->nwaiters == 1) && stored->cleanup)
+ _StatCleanup(stored);
+ else
+ stored->nwaiters--;
+ pthread_mutex_unlock(&(stored->mtx));
+ }
+ if ((code == EINTR) || (code == ETIMEDOUT)) {
+ afscp_errno = code;
+ code = -1;
+ }
+ return code;
+}
+
int
afscp_GetStatus(const struct afscp_venusfid *fid, struct AFSFetchStatus *s)
{
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;
}
}
int
+afscp_CheckCallBack(const struct afscp_venusfid *fid, const struct afscp_server *server, afs_uint32 *expiretime)
+{
+ struct AFSFetchStatus status;
+ struct afscp_callback *cb = NULL;
+ int code;
+ time_t now;
+
+ if (expiretime == NULL || fid == NULL) {
+ fprintf(stderr, "NULL args given to afscp_CheckCallback, cannot continue\n");
+ return -1;
+ }
+
+ *expiretime = 0;
+
+ code = afscp_GetStatus(fid, &status);
+ if (code != 0)
+ return code;
+
+ code = afscp_FindCallBack(fid, server, cb);
+ if (code != 0)
+ return code;
+
+ if (cb) {
+ time(&now);
+ *expiretime = cb->cb.ExpirationTime + cb->as_of - now;
+ }
+
+ return 0;
+}
+
+int
_StatInvalidate(const struct afscp_venusfid *fid)
{
struct afscp_volume *v;
- struct afscp_statent key;
+ struct afscp_statent *stored, key;
void **cached;
v = afscp_VolumeById(fid->cell, fid->fid.Volume);
cached = tfind(&key, &v->statcache, statcompare);
if (cached != NULL) {
- free(*cached);
+ stored = *(struct afscp_statent **)cached;
+ pthread_mutex_lock(&(stored->mtx));
tdelete(&key, &v->statcache, statcompare);
+ if (stored->nwaiters) {
+ /* avoid blocking callback thread */
+ pthread_cond_broadcast(&(stored->cv));
+ stored->cleanup = 1;
+ } else
+ _StatCleanup(stored);
+ pthread_mutex_unlock(&(stored->mtx));
}
return 0;
}
if (cached != NULL) {
stored = malloc(sizeof(struct afscp_statent));
if (stored != NULL) {
+ pthread_mutex_init(&(stored->mtx), NULL);
+ pthread_cond_init(&(stored->cv), NULL);
+ stored->nwaiters = 0;
+ stored->cleanup = 0;
memmove(&stored->me, fid, sizeof(*fid));
memmove(&stored->status, s, sizeof(*s));
*(struct afscp_statent **)cached = stored;
pthread_key_t uclient_key;
#endif
+static int lockFile(struct cmd_syndesc *, void *);
static int readFile(struct cmd_syndesc *, void *);
static int writeFile(struct cmd_syndesc *, void *);
static void printDatarate(void);
static int verbose = 0; /* Set if -verbose option given */
static int cellGiven = 0; /* Set if -cell option given */
static int force = 0; /* Set if -force option given */
+static int readlock = 0; /* Set if -readlock option given */
+static int waittime = 0; /* Set if -waittime option given */
static int useFid = 0; /* Set if fidwrite/fidread/fidappend invoked */
static int append = 0; /* Set if append/fidappend invoked */
static struct timeval starttime, opentime, readtime, writetime;
*slp = pdp->items->data;
else if (strcmp(pdp->name, "-realm") == 0)
*realmp = pdp->items->data;
+ else if (strcmp(pdp->name, "-wait") == 0)
+ waittime = atoi(pdp->items->data);
+ else if (strcmp(pdp->name, "-readlock") == 0)
+ readlock = 1;
}
}
return 0;
assert(pthread_key_create(&uclient_key, NULL) == 0);
#endif
- ts = cmd_CreateSyntax("read", readFile, CMD_REQUIRED,
+ ts = cmd_CreateSyntax("lock", lockFile, (void *)LockWrite,
+ "lock a file in AFS");
+ cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
+ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
+ cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+ cmd_Seek(ts, 4);
+ cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
+ cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
+ cmd_AddParm(ts, "-readlock", CMD_FLAG, CMD_OPTIONAL, "read lock only");
+
+ ts = cmd_CreateSyntax("fidlock", lockFile, (void *)LockWrite,
+ "lock by FID a file from AFS");
+ cmd_IsAdministratorCommand(ts);
+ cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
+ "volume.vnode.uniquifier");
+ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
+ cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+ cmd_Seek(ts, 4);
+ cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
+ cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
+ cmd_AddParm(ts, "-readlock", CMD_FLAG, CMD_OPTIONAL, "read lock only");
+
+ ts = cmd_CreateSyntax("unlock", lockFile, (void *)LockRelease,
+ "unlock a file in AFS");
+ cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
+ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
+ cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+ cmd_Seek(ts, 4);
+ cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
+ cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
+
+ ts = cmd_CreateSyntax("fidunlock", lockFile, (void *)LockRelease,
+ "unlock by FID a file from AFS");
+ cmd_IsAdministratorCommand(ts);
+ cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
+ "volume.vnode.uniquifier");
+ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
+ cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+ cmd_Seek(ts, 4);
+ cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
+ cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
+
+ ts = cmd_CreateSyntax("read", readFile, NULL,
"read a file from AFS");
cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
- ts = cmd_CreateSyntax("write", writeFile, CMD_REQUIRED,
+ ts = cmd_CreateSyntax("write", writeFile, NULL,
"write a file into AFS");
cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
"overwrite existing file");
cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
- ts = cmd_CreateSyntax("append", writeFile, CMD_REQUIRED,
+ ts = cmd_CreateSyntax("append", writeFile, NULL,
"append to a file in AFS");
cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
- ts = cmd_CreateSyntax("fidappend", writeFile, CMD_REQUIRED,
+ ts = cmd_CreateSyntax("fidappend", writeFile, NULL,
"append to a file in AFS");
cmd_IsAdministratorCommand(ts);
cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED,
} /* GetVenusFidByPath */
static int
+lockFile(struct cmd_syndesc *as, void *arock)
+{
+ char *fname = NULL;
+ char *cell = NULL;
+ char *realm = NULL;
+ afs_int32 code = 0;
+ struct AFSFetchStatus OutStatus;
+ struct afscp_venusfid *avfp = NULL;
+ char *buf = 0;
+ char ipv4_addr[16];
+ int locktype = (int)(intptr_t) arock;
+
+#ifdef AFS_NT40_ENV
+ /* stdout on Windows defaults to _O_TEXT mode */
+ _setmode(1, _O_BINARY);
+#endif
+
+ gettimeofday(&starttime, &Timezone);
+
+ CmdProlog(as, &cell, &realm, &fname, NULL);
+ afscp_AnonymousAuth(1);
+
+ if ((locktype == LockWrite) && readlock)
+ locktype = LockRead;
+
+ if (realm != NULL)
+ code = afscp_SetDefaultRealm(realm);
+
+ if (cell != NULL)
+ code = afscp_SetDefaultCell(cell);
+
+ if (useFid)
+ code = GetVenusFidByFid(fname, cell, 0, &avfp);
+ else
+ code = GetVenusFidByPath(fname, cell, &avfp);
+ if (code != 0) {
+ afs_com_err(pnp, code, "(file not found: %s)", fname);
+ return code;
+ }
+
+retry:
+ code = afscp_GetStatus(avfp, &OutStatus);
+ if (code != 0) {
+ afs_inet_ntoa_r(avfp->cell->fsservers[0]->addrs[0], ipv4_addr);
+ afs_com_err(pnp, code, "(failed to get status of file %s from"
+ "server %s, code = %d)", fname, ipv4_addr, code);
+ afscp_FreeFid(avfp);
+ return code;
+ }
+
+ if (locktype != LockRelease) {
+ while (OutStatus.lockCount != 0) {
+ code = afscp_WaitForCallback(avfp, waittime);
+ if ((code == -1) && (afscp_errno == ETIMEDOUT))
+ break;
+ if ((code = afscp_GetStatus(avfp, &OutStatus)) != 0)
+ break;
+ }
+ } else {
+ if (OutStatus.lockCount == 0) {
+ code = -1;
+ }
+ }
+
+ if (!code) {
+ code = afscp_Lock(avfp, locktype);
+ if ((code == -1) && (afscp_errno == EWOULDBLOCK))
+ goto retry;
+ }
+ afscp_FreeFid(avfp);
+
+ if (buf != NULL)
+ free(buf);
+
+ if (code != 0)
+ afs_com_err(pnp, code, "(failed to change lock status: %d)", afscp_errno);
+
+ return code;
+} /* lockFile */
+
+static int
readFile(struct cmd_syndesc *as, void *unused)
{
char *fname = NULL;
gettimeofday(&starttime, &Timezone);
InStatus.UnixModeBits = 0644;
+ InStatus.Mask = AFS_SETMODE + AFS_FSYNC;
if (newvfp == NULL) {
code = afscp_CreateFile(dirvfp, baseName, &InStatus, &newvfp);
if (code != 0) {
return code;
}
- InStatus.Mask = AFS_SETMODE + AFS_FSYNC;
if (append) {
Pos = OutStatus.Length_hi;
Pos = (Pos << 32) | OutStatus.Length;