struct afs_osi_WaitHandle AFS_WaitHandler, AFS_CSWaitHandler;
static int afs_brs_count = 0; /* request counter, to service reqs in order */
-static int rxepoch_checked = 0;
-#define afs_CheckRXEpoch() {if (rxepoch_checked == 0 && rxkad_EpochWasSet) { \
- rxepoch_checked = 1; afs_GCUserData(/* force flag */ 1); } }
-
/* PAG garbage collection */
/* We induce a compile error if param.h does not define AFS_GCPAGS */
afs_int32 afs_gcpags = AFS_GCPAGS;
afs_int32 last3MinCheck, last10MinCheck, last60MinCheck, lastNMinCheck;
afs_int32 last1MinCheck, last5MinCheck;
afs_uint32 lastCBSlotBump;
- char cs_warned = 0;
AFS_STATCNT(afs_Daemon);
- last1MinCheck = last3MinCheck = last60MinCheck = last10MinCheck =
- last5MinCheck = lastNMinCheck = 0;
afs_rootFid.Fid.Volume = 0;
while (afs_initState < 101)
if (last1MinCheck + 60 < now) {
/* things to do every minute */
DFlush(); /* write out dir buffers */
- afs_WriteThroughDSlots(); /* write through cacheinfo entries */
+ (void)afs_WriteThroughDSlots(); /* write through cacheinfo entries */
ObtainWriteLock(&afs_xvcache, 736);
afs_FlushReclaimedVcaches();
ReleaseWriteLock(&afs_xvcache);
afs_FlushActiveVcaches(1); /* keep flocks held & flush nfs writes */
-#if 0
- afs_StoreDirtyVcaches();
-#endif
- afs_CheckRXEpoch();
last1MinCheck = now;
}
}
if (!afs_CheckServerDaemonStarted) {
- /* Do the check here if the correct afsd is not installed. */
- if (!cs_warned) {
- cs_warned = 1;
- afs_warn("Please install afsd with check server daemon.\n");
- }
if (lastNMinCheck + afs_probe_interval < now) {
/* only check down servers */
afs_CheckServers(1, NULL);
#endif /* else AFS_USERSPACE_IP_ADDR */
if (!afs_CheckServerDaemonStarted)
afs_CheckServers(0, NULL);
- afs_GCUserData(0); /* gc old conns */
+ afs_GCUserData(); /* gc old conns */
/* This is probably the wrong way of doing GC for the various exporters but it will suffice for a while */
for (exporter = root_exported; exporter;
exporter = exporter->exp_next) {
int
afs_CheckRootVolume(void)
{
- char rootVolName[32];
+ char rootVolName[MAXROOTVOLNAMELEN];
struct volume *tvp = NULL;
int usingDynroot = afs_GetDynrootEnable();
int localcell;
* count to zero and fs checkv is executed when the current
* directory is /afs.
*/
-#ifdef AFS_LINUX20_ENV
- {
- struct vrequest treq;
- struct vattr vattr;
- cred_t *credp;
- struct dentry *dp;
- struct vcache *vcp;
-
- afs_rootFid.Fid.Volume = volid;
- afs_rootFid.Fid.Vnode = 1;
- afs_rootFid.Fid.Unique = 1;
-
- credp = crref();
- if (afs_InitReq(&treq, credp))
- goto out;
- vcp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
- if (!vcp)
- goto out;
- afs_getattr(vcp, &vattr, credp);
- afs_fill_inode(AFSTOV(vcp), &vattr);
-
- dp = d_find_alias(AFSTOV(afs_globalVp));
-
-#if defined(AFS_LINUX24_ENV)
-#if defined(HAVE_DCACHE_LOCK)
- spin_lock(&dcache_lock);
-#else
- spin_lock(&AFSTOV(vcp)->i_lock);
-#endif
-#if defined(AFS_LINUX26_ENV)
- spin_lock(&dp->d_lock);
-#endif
-#endif
-#if defined(D_ALIAS_IS_HLIST)
- hlist_del_init(&dp->d_alias);
- hlist_add_head(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
-#else
- list_del_init(&dp->d_alias);
- list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
-#endif
- dp->d_inode = AFSTOV(vcp);
-#if defined(AFS_LINUX24_ENV)
-#if defined(AFS_LINUX26_ENV)
- spin_unlock(&dp->d_lock);
-#endif
-#if defined(HAVE_DCACHE_LOCK)
- spin_unlock(&dcache_lock);
-#else
- spin_unlock(&AFSTOV(vcp)->i_lock);
-#endif
-#endif
- dput(dp);
-
- AFS_FAST_RELE(afs_globalVp);
- afs_globalVp = vcp;
- out:
- crfree(credp);
- }
+#ifdef AFS_LINUX22_ENV
+ osi_ResetRootVCache(volid);
#else
-#ifdef AFS_DARWIN80_ENV
+# ifdef AFS_DARWIN80_ENV
afs_PutVCache(afs_globalVp);
-#else
+# else
AFS_FAST_RELE(afs_globalVp);
-#endif
+# endif
afs_globalVp = 0;
#endif
}
struct dentry *dp = NULL;
#endif
afs_size_t offset, len;
- struct vrequest treq;
+ struct vrequest *treq = NULL;
afs_int32 code;
AFS_STATCNT(BPath);
- if ((code = afs_InitReq(&treq, ab->cred)))
+ if ((code = afs_CreateReq(&treq, ab->cred))) {
return;
+ }
AFS_GUNLOCK();
#ifdef AFS_LINUX22_ENV
code = gop_lookupname((char *)ab->ptr_parm[0], AFS_UIOSYS, 1, &dp);
#endif
AFS_GLOCK();
osi_FreeLargeSpace((char *)ab->ptr_parm[0]); /* free path name buffer here */
- if (code)
+ if (code) {
+ afs_DestroyReq(treq);
return;
+ }
/* now path may not have been in afs, so check that before calling our cache manager */
if (!tvn || !IsAfsVnode(tvn)) {
/* release it and give up */
AFS_RELE(tvn);
#endif
}
+ afs_DestroyReq(treq);
return;
}
tvc = VTOAFS(tvn);
/* here we know its an afs vnode, so we can get the data for the chunk */
- tdc = afs_GetDCache(tvc, ab->size_parm[0], &treq, &offset, &len, 1);
+ tdc = afs_GetDCache(tvc, ab->size_parm[0], treq, &offset, &len, 1);
if (tdc) {
afs_PutDCache(tdc);
}
#else
AFS_RELE(tvn);
#endif
+ afs_DestroyReq(treq);
}
/* size_parm 0 to the fetch is the chunk number,
struct dcache *tdc;
struct vcache *tvc;
afs_size_t offset, len, abyte, totallen = 0;
- struct vrequest treq;
+ struct vrequest *treq = NULL;
+ int code;
AFS_STATCNT(BPrefetch);
- if ((len = afs_InitReq(&treq, ab->cred)))
+ if ((code = afs_CreateReq(&treq, ab->cred)))
return;
abyte = ab->size_parm[0];
tvc = ab->vc;
do {
- tdc = afs_GetDCache(tvc, abyte, &treq, &offset, &len, 1);
+ tdc = afs_GetDCache(tvc, abyte, treq, &offset, &len, 1);
if (tdc) {
afs_PutDCache(tdc);
}
if (ab->size_parm[1]) {
afs_PutDCache(tdc); /* put this one back, too */
}
+ afs_DestroyReq(treq);
}
#if defined(AFS_CACHE_BYPASS)
static void
BPrefetchNoCache(struct brequest *ab)
{
- struct vrequest treq;
- afs_size_t len;
+ struct vrequest *treq = NULL;
+ int code;
- if ((len = afs_InitReq(&treq, ab->cred)))
+ if ((code = afs_CreateReq(&treq, ab->cred)))
return;
#ifndef UKERNEL
/* OS-specific prefetch routine */
afs_PrefetchNoCache(ab->vc, ab->cred, (struct nocache_read_request *) ab->ptr_parm[0]);
#endif
+ afs_DestroyReq(treq);
}
#endif
{
struct vcache *tvc;
afs_int32 code;
- struct vrequest treq;
+ struct vrequest *treq = NULL;
#if defined(AFS_SGI_ENV)
struct cred *tmpcred;
#endif
AFS_STATCNT(BStore);
- if ((code = afs_InitReq(&treq, ab->cred)))
+ if ((code = afs_CreateReq(&treq, ab->cred)))
return;
- code = 0;
tvc = ab->vc;
#if defined(AFS_SGI_ENV)
/*
AFS_RWLOCK((vnode_t *) tvc, 1);
#endif
ObtainWriteLock(&tvc->lock, 209);
- code = afs_StoreOnLastReference(tvc, &treq);
+ code = afs_StoreOnLastReference(tvc, treq);
ReleaseWriteLock(&tvc->lock);
#if defined(AFS_SGI_ENV)
OSI_SET_CURRENT_CRED(tmpcred);
#endif
/* now set final return code, and wakeup anyone waiting */
if ((ab->flags & BUVALID) == 0) {
- ab->code = afs_CheckCode(code, &treq, 43); /* set final code, since treq doesn't go across processes */
+
+ /* To explain code_raw/code_checkcode:
+ * Anyone that's waiting won't have our treq, so they won't be able to
+ * call afs_CheckCode themselves on the return code we provide here.
+ * But if we give back only the afs_CheckCode value, they won't know
+ * what the "raw" value was. So give back both values, so the waiter
+ * can know the "raw" value for interpreting the value internally, as
+ * well as the afs_CheckCode value to give to the OS. */
+ ab->code_raw = code;
+ ab->code_checkcode = afs_CheckCode(code, treq, 430);
+
ab->flags |= BUVALID;
if (ab->flags & BUWAIT) {
ab->flags &= ~BUWAIT;
afs_osi_Wakeup(ab);
}
}
+ afs_DestroyReq(treq);
}
static void
{
struct vcache *tvc;
afs_int32 code;
- struct vrequest treq;
+ struct vrequest *treq = NULL;
int locked, shared_locked = 0;
AFS_STATCNT(BStore);
- if ((code = afs_InitReq(&treq, ab->cred)))
+ if ((code = afs_CreateReq(&treq, ab->cred)))
return;
- code = 0;
tvc = ab->vc;
locked = tvc->lock.excl_locked? 1:0;
if (!locked)
shared_locked = 1;
ConvertSToRLock(&tvc->lock);
}
- code = afs_StoreAllSegments(tvc, &treq, AFS_ASYNC);
+ code = afs_StoreAllSegments(tvc, treq, AFS_ASYNC);
if (!locked)
ReleaseWriteLock(&tvc->lock);
else if (shared_locked)
/* now set final return code, and wakeup anyone waiting */
if ((ab->flags & BUVALID) == 0) {
/* set final code, since treq doesn't go across processes */
- ab->code = afs_CheckCode(code, &treq, 43);
+ ab->code_raw = code;
+ ab->code_checkcode = afs_CheckCode(code, treq, 43);
ab->flags |= BUVALID;
if (ab->flags & BUWAIT) {
ab->flags &= ~BUWAIT;
afs_osi_Wakeup(ab);
}
}
+ afs_DestroyReq(treq);
+}
+
+static void
+BInvalidateSegments(struct brequest *ab)
+{
+ int code;
+ struct vcache *tvc = ab->vc;
+ osi_Assert(WriteLocked(&tvc->lock));
+
+ code = afs_InvalidateAllSegments_once(tvc);
+
+ /* Set return code, and wakeup anyone waiting. */
+ if ((ab->flags & BUVALID) == 0) {
+ ab->code_raw = ab->code_checkcode = code;
+ ab->flags |= BUVALID;
+ if ((ab->flags & BUWAIT)) {
+ ab->flags &= ~BUWAIT;
+ afs_osi_Wakeup(ab);
+ }
+ }
}
/* release a held request buffer */
tb->opcode = aopcode;
tb->vc = avc;
tb->cred = acred;
- crhold(tb->cred);
+ if (tb->cred) {
+ crhold(tb->cred);
+ }
if (avc) {
- AFS_FAST_HOLD(avc);
+ osi_Assert(osi_vnhold(avc) == 0);
}
tb->refCount = ause + 1;
tb->size_parm[0] = asparm0;
tb->ptr_parm[1] = apparm1;
tb->ptr_parm[2] = apparm2;
tb->flags = 0;
- tb->code = 0;
+ tb->code_raw = tb->code_checkcode = 0;
tb->ts = afs_brs_count++;
/* if daemons are waiting for work, wake them up */
if (afs_brsDaemons > 0) {
}
#ifdef AFS_NEW_BKG
+static_inline int
+should_do_noop(int foundAny, int n_processed)
+{
+ if (!foundAny && n_processed > 0) {
+ /* If there aren't any requests right now, and we've processed
+ * at least one request, do a noop. */
+ return 1;
+ } else if (foundAny && n_processed > 100) {
+ /* If we've processed over 100 requests in a row, do a noop. */
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/**
+ * Entry point for background daemon processes.
+ *
+ * For old-style background daemons (non-AFS_NEW_BKG), a background daemon afsd
+ * process will end up in this function, and it will stay in here forever
+ * processing in-kernel bkg requests until the client shuts down.
+ *
+ * For new-style background daemons (AFS_NEW_BKG), we can pass data back to
+ * afsd to perform some background operations in userspace, by populating
+ * 'uspc' with the operation to perform and then returning. When the afsd
+ * process enters this function again, the return code for that operation is
+ * also provided in 'uspc'.
+ *
+ * @param[inout] uspc Userspace operation data. If uspc->ts is non-negative
+ * on entry, the related background request has finished,
+ * and we're providing the return code. On return,
+ * contains the userspace operation to perform.
+ * @param[inout] param1 Operation-specific pointer.
+ * @param[inout] param2 Operation-specific pointer.
+ *
+ * @return Always returns 0.
+ */
+#ifdef AFS_NEW_BKG
int
afs_BackgroundDaemon(struct afs_uspc_param *uspc, void *param1, void *param2)
#else
{
struct brequest *tb;
int i, foundAny;
+ int n_processed = 0;
AFS_STATCNT(afs_BackgroundDaemon);
/* initialize subsystem */
afs_BackgroundDaemon_once();
#ifdef AFS_NEW_BKG
- /* If it's a re-entering syscall, complete the request and release */
- if (uspc->ts > -1) {
+ if (uspc->reqtype == AFS_USPC_NOOP) {
+ /* The daemon is re-entering from a noop, not actually returning data;
+ * don't look for an existing request. */
+ /* noop */
+
+ } else if (uspc->ts > -1) {
+ /* If it's a re-entering syscall, complete the request and release */
tb = afs_brs;
for (i = 0; i < NBRS; i++, tb++) {
if (tb->ts == uspc->ts) {
/* copy the userspace status back in */
- ((struct afs_uspc_param *) tb->ptr_parm[0])->retval =
- uspc->retval;
+ tb->code_raw = tb->code_checkcode = uspc->retval;
/* mark it valid and notify our caller */
tb->flags |= BUVALID;
if (tb->flags & BUWAIT) {
ReleaseWriteLock(&afs_xbrs);
afs_osi_Wakeup(&afs_termState);
#ifdef AFS_NEW_BKG
- return -2;
+ memset(uspc, 0, sizeof(*uspc));
+ uspc->reqtype = AFS_USPC_SHUTDOWN;
+ return 0;
#else
return;
#endif
tb->flags |= BSTARTED;
ReleaseWriteLock(&afs_xbrs);
foundAny = 1;
+ n_processed++;
afs_Trace1(afs_iclSetp, CM_TRACE_BKG1, ICL_TYPE_INT32,
tb->opcode);
if (tb->opcode == BOP_FETCH)
#endif
else if (tb->opcode == BOP_PARTIAL_STORE)
BPartialStore(tb);
+ else if (tb->opcode == BOP_INVALIDATE_SEGMENTS)
+ BInvalidateSegments(tb);
else
panic("background bop");
brequest_release(tb);
ObtainWriteLock(&afs_xbrs, 305);
}
+
+#ifdef AFS_NEW_BKG
+ if (should_do_noop(foundAny, n_processed)) {
+ ReleaseWriteLock(&afs_xbrs);
+ memset(uspc, 0, sizeof(*uspc));
+ uspc->reqtype = AFS_USPC_NOOP;
+ return 0;
+ }
+#endif
+
if (!foundAny) {
/* wait for new request */
afs_brsDaemons++;
AFS_STATCNT(shutdown_daemons);
if (afs_cold_shutdown) {
afs_brsDaemons = brsInit = 0;
- rxepoch_checked = afs_nbrs = 0;
+ afs_nbrs = 0;
memset(afs_brs, 0, sizeof(afs_brs));
memset(&afs_xbrs, 0, sizeof(afs_lock_t));
afs_brsWaiters = 0;