#include "rx/rx_globals.h"
#include "token.h"
+extern int afs_rmtsys_enable;
struct VenusFid afs_rootFid;
afs_int32 afs_waitForever = 0;
short afs_waitForeverCount = 0;
static_inline int
afs_pd_alloc(struct afs_pdata *apd, size_t size)
{
-
- if (size > AFS_LRALLOCSIZ)
+ /* Ensure that we give caller at least one trailing guard byte
+ * for the NUL terminator. */
+ if (size >= AFS_LRALLOCSIZ)
apd->ptr = osi_Alloc(size + 1);
else
apd->ptr = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
if (apd->ptr == NULL)
return ENOMEM;
+ /* Clear it all now, including the guard byte. */
+ if (size >= AFS_LRALLOCSIZ)
+ memset(apd->ptr, 0, size + 1);
+ else
+ memset(apd->ptr, 0, AFS_LRALLOCSIZ);
+
+ /* Don't tell the caller about the guard byte. */
apd->remaining = size;
return 0;
if (apd->ptr == NULL)
return;
- if (apd->remaining > AFS_LRALLOCSIZ)
+ if (apd->remaining >= AFS_LRALLOCSIZ)
osi_Free(apd->ptr, apd->remaining + 1);
else
osi_FreeLargeSpace(apd->ptr);
DECL_PIOCTL(PGetCellStatus);
DECL_PIOCTL(PSetCellStatus);
DECL_PIOCTL(PFlushVolumeData);
+DECL_PIOCTL(PFlushAllVolumeData);
DECL_PIOCTL(PGetVnodeXStatus);
DECL_PIOCTL(PGetVnodeXStatus2);
DECL_PIOCTL(PSetSysName);
DECL_PIOCTL(PNewUuid);
DECL_PIOCTL(PPrecache);
DECL_PIOCTL(PGetPAG);
-#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX_ENV)
DECL_PIOCTL(PSetCachingThreshold);
#endif
PBogus, /* 11 */
PPrecache, /* 12 */
PGetPAG, /* 13 */
+ PFlushAllVolumeData, /* 14 */
};
static pioctlFunction OpioctlSw[] = {
PBogus, /* 0 */
PNFSNukeCreds, /* 1 -- nuke all creds for NFS client */
-#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX_ENV)
PSetCachingThreshold /* 2 -- get/set cache-bypass size threshold */
#else
PNoop /* 2 -- get/set cache-bypass size threshold */
if (((uap->com >> 8) & 0xff) == 'V') {
struct afs_ioctl *datap;
AFS_GLOCK();
- datap =
- (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+ datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
code=copyin_afs_ioctl((char *)uap->arg, datap);
if (code) {
osi_FreeSmallSpace(datap);
if (((uap->com >> 8) & 0xff) == 'V') {
struct afs_ioctl *datap;
AFS_GLOCK();
- datap =
- (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+ datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
code=copyin_afs_ioctl((char *)uap->arg, datap);
if (code) {
osi_FreeSmallSpace(datap);
return (code);
}
-#elif defined(AFS_LINUX22_ENV)
+#elif defined(AFS_LINUX_ENV)
struct afs_ioctl_sys {
unsigned int com;
unsigned long arg;
#if defined(AFS_NBSD50_ENV)
if ((fd = fd_getfile(SCARG(uap, fd))) == NULL)
return (EBADF);
+#elif defined(AFS_FBSD_ENV)
+ if ((uap->fd >= fdp->fd_nfiles)
+ || ((fd = fdp->fd_ofiles[uap->fd].fde_file) == NULL))
+ return EBADF;
#else
if ((uap->fd >= fdp->fd_nfiles)
|| ((fd = fdp->fd_ofiles[uap->fd]) == NULL))
if (!ioctlDone) {
# if defined(AFS_FBSD_ENV)
-# if (__FreeBSD_version >= 900044)
return sys_ioctl(td, uap);
-# else
- return ioctl(td, uap);
-# endif
# elif defined(AFS_OBSD_ENV)
code = sys_ioctl(p, uap, retval);
# elif defined(AFS_NBSD_ENV)
#endif
/* macro to avoid adding any more #ifdef's to pioctl code. */
-#if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
+#if defined(AFS_LINUX_ENV) || defined(AFS_AIX41_ENV)
#define PIOCTL_FREE_CRED() crfree(credp)
#else
#define PIOCTL_FREE_CRED()
#ifdef AFS_NEED_CLIENTCONTEXT
afs_ucred_t *tmpcred = NULL;
#endif
-#if defined(AFS_NEED_CLIENTCONTEXT) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#if defined(AFS_NEED_CLIENTCONTEXT) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
afs_ucred_t *foreigncreds = NULL;
#endif
afs_int32 code = 0;
#ifdef AFS_AIX41_ENV
struct ucred *credp = crref(); /* don't free until done! */
#endif
-#ifdef AFS_LINUX22_ENV
+#ifdef AFS_LINUX_ENV
cred_t *credp = crref(); /* don't free until done! */
struct dentry *dp;
#endif
}
if ((com & 0xff) == PSetClientContext) {
#ifdef AFS_NEED_CLIENTCONTEXT
-#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX_ENV)
code = HandleClientContext(&data, &com, &foreigncreds, credp);
#else
code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
* like afs_osi_suser(cred) which, I think, is better since it
* generalizes and supports multi cred environments...
*/
-#if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_LINUX_ENV)
tmpcred = credp;
credp = foreigncreds;
#elif defined(AFS_AIX41_ENV)
#endif
}
#endif /* AFS_NEED_CLIENTCONTEXT */
- if ((com & 0xff) == 15) {
+
+ /* VIOCPREFETCH */
+ if ((com & 0xff00) >> 8 == 'V' && (com & 0xff) == 15) {
/* special case prefetch so entire pathname eval occurs in helper process.
* otherwise, the pioctl call is essentially useless */
-#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
code =
Prefetch(path, &data, follow,
foreigncreds ? foreigncreds : credp);
lookupname(path, USR, follow, NULL, &vp,
foreigncreds ? foreigncreds : credp);
#else
-#ifdef AFS_LINUX22_ENV
+#ifdef AFS_LINUX_ENV
code = gop_lookupname_user(path, AFS_UIOUSER, follow, &dp);
if (!code)
vp = (struct vnode *)dp->d_inode;
#else
code = gop_lookupname_user(path, AFS_UIOUSER, follow, &vp);
-#if defined(AFS_FBSD80_ENV) /* XXX check on 7x */
- if (vp != NULL)
- VN_HOLD(vp);
-#endif /* AFS_FBSD80_ENV */
-#endif /* AFS_LINUX22_ENV */
+#endif /* AFS_LINUX_ENV */
#endif /* AFS_AIX41_ENV */
AFS_GLOCK();
if (code) {
credp = OSI_GET_CURRENT_CRED();
code = afs_HandlePioctl(vp, com, &data, follow, &credp);
}
-#elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+#elif defined(AFS_LINUX_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
code = afs_HandlePioctl(vp, com, &data, follow, &credp);
#elif defined(UKERNEL)
code = afs_HandlePioctl(vp, com, &data, follow,
set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
#elif defined(AFS_SGI_ENV)
OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
-#elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
+#elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX_ENV)
credp = tmpcred; /* restore original credentials */
#else
osi_curcred() = tmpcred; /* restore original credentials */
}
#endif /* AFS_NEED_CLIENTCONTEXT */
if (vp) {
-#ifdef AFS_LINUX22_ENV
+#ifdef AFS_LINUX_ENV
+ /*
+ * Holding the global lock when calling dput can cause a deadlock
+ * when the kernel calls back into afs_dentry_iput
+ */
+ AFS_GUNLOCK();
dput(dp);
+ AFS_GLOCK();
#else
-#if defined(AFS_FBSD80_ENV)
+#if defined(AFS_FBSD_ENV)
if (VOP_ISLOCKED(vp))
VOP_UNLOCK(vp, 0);
-#endif /* AFS_FBSD80_ENV */
+#endif /* AFS_FBSD_ENV */
AFS_RELE(vp); /* put vnode back */
#endif
}
afs_ucred_t **acred)
{
struct vcache *avc;
- struct vrequest treq;
+ struct vrequest *treq = NULL;
afs_int32 code;
afs_int32 function, device;
struct afs_pdata input, output;
ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
AFS_STATCNT(HandlePioctl);
- code = afs_InitReq(&treq, *acred);
+ code = afs_CreateReq(&treq, *acred);
if (code)
return code;
afs_InitFakeStat(&fakestate);
if (avc) {
- code = afs_EvalFakeStat(&avc, &fakestate, &treq);
+ code = afs_EvalFakeStat(&avc, &fakestate, treq);
if (code)
goto out;
}
copyOutput = output;
code =
- (*pioctlSw[function]) (avc, function, &treq, ©Input,
+ (*pioctlSw[function]) (avc, function, treq, ©Input,
©Output, acred);
outSize = copyOutput.ptr - output.ptr;
afs_pd_free(&output);
afs_PutFakeStat(&fakestate);
- return afs_CheckCode(code, &treq, 41);
+ code = afs_CheckCode(code, treq, 41);
+ afs_DestroyReq(treq);
+ return code;
}
/*!
SHARED_LOCK, NULL));
/* now we've forgotten all of the access info */
- ObtainWriteLock(&afs_xcbhash, 455);
- avc->callback = 0;
- afs_DequeueCallback(avc);
- avc->f.states &= ~(CStatd | CUnique);
- ReleaseWriteLock(&afs_xcbhash);
- if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
- osi_dnlc_purgedp(avc);
+ afs_StaleVCacheFlags(avc, AFS_STALEVC_CLEARCB, CUnique);
/* SXW - Should we flush metadata here? */
+
return code;
}
}
+#if defined(AFS_LINUX_ENV)
static_inline int
-_settok_setParentPag(afs_ucred_t **cred) {
+_settok_setParentPag(afs_ucred_t **cred)
+{
+ afs_uint32 pag;
+ int code;
+ afs_ucred_t *old_cred = *cred;
+ code = setpag(cred, -1, &pag, 1);
+ if (code == 0) {
+ /* setpag() may have changed our credentials */
+ *cred = crref();
+ crfree(old_cred);
+ }
+ return code;
+}
+#elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
+static_inline int
+_settok_setParentPag(afs_ucred_t **cred)
+{
afs_uint32 pag;
-#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
char procname[256];
osi_procname(procname, 256);
afs_warnuser("Process %d (%s) tried to change pags in PSetTokens\n",
MyPidxx2Pid(MyPidxx), procname);
return setpag(osi_curproc(), cred, -1, &pag, 1);
+}
#else
+static_inline int
+_settok_setParentPag(afs_ucred_t **cred)
+{
+ afs_uint32 pag;
return setpag(cred, -1, &pag, 1);
-#endif
}
+#endif
/*!
* VIOCSETTOK (3) - Set authentication tokens
char *stp;
char *cellName;
int stLen;
- struct vrequest treq;
+ struct vrequest *treq = NULL;
afs_int32 flag, set_parent_pag = 0;
AFS_STATCNT(PSetTokens);
if (set_parent_pag) {
if (_settok_setParentPag(acred) == 0) {
- afs_InitReq(&treq, *acred);
- areq = &treq;
+ code = afs_CreateReq(&treq, *acred);
+ if (code) {
+ return code;
+ }
+ areq = treq;
}
}
afs_ResetUserConns(tu);
afs_NotifyUser(tu, UTokensObtained);
afs_PutUser(tu, WRITE_LOCK);
+ afs_DestroyReq(treq);
return 0;
}
AFS_STATCNT(PSetVolumeStatus);
if (!avc)
return EINVAL;
+ memset(&storeStat, 0, sizeof(storeStat));
tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
if (tvp) {
AFS_STATCNT(PFlush);
if (!avc)
return EINVAL;
-#ifdef AFS_BOZONLOCK_ENV
- afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
-#endif
ObtainWriteLock(&avc->lock, 225);
- afs_ResetVCache(avc, *acred);
+ afs_ResetVCache(avc, *acred, 0);
ReleaseWriteLock(&avc->lock);
-#ifdef AFS_BOZONLOCK_ENV
- afs_BozonUnlock(&avc->pvnLock, avc);
-#endif
return 0;
}
/*!
+ * Lookup name in the directory associated with given vcache.
+ *
+ * \param[in] avc vcache associated with directory
+ * \param[in] areq request to be passed on
+ * \param[in] aname name to be searched
+ * \param[out] asys resolved name (replace @sys by system type)
+ * \param[out] afid fid associated with aname
+ *
+ * \return 0 on success; non-zero otherwise.
+ *
+ * \notes The caller must free asys->name (checking if asys->allocked == 1).
+ */
+static int
+afs_LookupName(struct vcache *avc, struct vrequest *areq, char *aname,
+ struct sysname_info *asys, struct VenusFid *afid)
+{
+ int code;
+ struct dcache *tdc;
+ afs_size_t offset, len;
+
+ memset(asys, 0, sizeof(*asys));
+ memset(afid, 0, sizeof(*afid));
+
+ if (!avc || !areq || !aname || !asys || !afid) {
+ afs_warn("afs: Internal error, bad args to afs_LookupName: %p, %p, %p, "
+ "%p, %p.\n", avc, areq, aname, asys, afid);
+ code = EIO;
+ goto done;
+ }
+
+ /* check if vcache is up to date */
+ code = afs_VerifyVCache(avc, areq);
+ if (code != 0) {
+ goto done;
+ }
+
+ /* must be a directory */
+ if (vType(avc) != VDIR) {
+ code = ENOTDIR;
+ goto done;
+ }
+
+ tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
+ if (!tdc) {
+ code = EIO;
+ goto done;
+ }
+
+ /* if @sys is present, replace it by the machine's system type */
+ Check_AtSys(avc, aname, asys, areq);
+ ObtainReadLock(&tdc->lock);
+
+ do {
+ /*
+ * Lookup name in the appropriate directory. If name is not found, try
+ * again with the next sysname from the @sys list.
+ */
+ code = afs_dir_Lookup(tdc, asys->name, &afid->Fid);
+ } while (code == ENOENT && Next_AtSys(avc, areq, asys));
+
+ ReleaseReadLock(&tdc->lock);
+ afs_PutDCache(tdc);
+ done:
+ return code;
+}
+
+/*!
* VIOC_AFS_STAT_MT_PT (29) - Stat mount point
*
* \ingroup pioctl
{
afs_int32 code;
struct vcache *tvc;
- struct dcache *tdc;
struct VenusFid tfid;
char *bufp;
char *name;
struct sysname_info sysState;
- afs_size_t offset, len;
AFS_STATCNT(PNewStatMount);
+ memset(&sysState, 0, sizeof(sysState));
+
if (!avc)
return EINVAL;
if (afs_pd_getStringPtr(ain, &name) != 0)
return EINVAL;
- code = afs_VerifyVCache(avc, areq);
- if (code)
- return code;
- if (vType(avc) != VDIR) {
- return ENOTDIR;
- }
- tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
- if (!tdc)
- return ENOENT;
- Check_AtSys(avc, name, &sysState, areq);
- ObtainReadLock(&tdc->lock);
- do {
- code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
- } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
- ReleaseReadLock(&tdc->lock);
- afs_PutDCache(tdc); /* we're done with the data */
- bufp = sysState.name;
+ code = afs_LookupName(avc, areq, name, &sysState, &tfid);
if (code) {
goto out;
}
+
+ bufp = sysState.name;
tfid.Cell = avc->f.fid.Cell;
tfid.Fid.Volume = avc->f.fid.Fid.Volume;
if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
- tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
+ tvc = afs_LookupVCache(&tfid, areq, avc, bufp);
} else {
- tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+ tvc = afs_GetVCache(&tfid, areq);
}
if (!tvc) {
- code = ENOENT;
+ code = EIO;
goto out;
}
- if (tvc->mvstat != 1) {
+ if (tvc->mvstat != AFS_MVSTAT_MTPT) {
afs_PutVCache(tvc);
code = EINVAL;
goto out;
afs_PutVCache(tvc);
out:
if (sysState.allocked)
- osi_FreeLargeSpace(bufp);
+ osi_FreeLargeSpace(sysState.name);
return code;
}
int i;
struct unixuser *tu = NULL;
+ if (iterator > afs_cellindex)
+ return NULL; /* no point in looking */
+
i = UHash(uid);
ObtainReadLock(&afs_xuser);
for (tu = afs_users[i]; tu; tu = tu->next) {
afs_int32 results[MAXGCSTATS];
afs_int32 flags;
struct dcache * tdc;
- int i, size;
+ int i;
AFS_STATCNT(PGetCacheSize);
tdc = afs_indexTable[i];
if (tdc){
+ afs_size_t size = tdc->validPos;
+
results[9]++;
- size = tdc->validPos;
- if ( 0 < size && size < (1<<12) ) results[10]++;
+ if ( 0 <= size && size < (1<<12) ) results[10]++;
else if (size < (1<<14) ) results[11]++;
else if (size < (1<<16) ) results[12]++;
else if (size < (1<<18) ) results[13]++;
(tc, rxconn, code, &avc->f.fid, areq,
AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
- ObtainWriteLock(&afs_xcbhash, 457);
- afs_DequeueCallback(avc);
- avc->callback = 0;
- avc->f.states &= ~(CStatd | CUnique);
- ReleaseWriteLock(&afs_xcbhash);
- if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
- osi_dnlc_purgedp(avc);
+ afs_StaleVCacheFlags(avc, AFS_STALEVC_CLEARCB, CUnique);
}
ReleaseWriteLock(&avc->lock);
return 0;
* This whole logic is bogus, because it relies on the newer command
* sending its 12th address as 0.
*/
- if ((afs_pd_remaining(ain) < AFS_MAXCELLHOSTS +3) * sizeof(afs_int32))
+ if (afs_pd_remaining(ain) < (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32))
return EINVAL;
newcell = afs_pd_where(ain) + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
if (!tdc)
- return ENOENT;
+ return EIO;
Check_AtSys(avc, name, &sysState, areq);
ObtainReadLock(&tdc->lock);
do {
tfid.Cell = avc->f.fid.Cell;
tfid.Fid.Volume = avc->f.fid.Fid.Volume;
if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
- tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
+ tvc = afs_LookupVCache(&tfid, areq, avc, bufp);
} else {
- tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+ tvc = afs_GetVCache(&tfid, areq);
}
if (!tvc) {
- code = ENOENT;
+ code = EIO;
afs_PutDCache(tdc);
goto out;
}
- if (tvc->mvstat != 1) {
+ if (tvc->mvstat != AFS_MVSTAT_MTPT) {
afs_PutDCache(tdc);
afs_PutVCache(tvc);
code = EINVAL;
return 0;
}
-/*!
- * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
- *
- * \ingroup pioctl
- *
- * \param[in] ain not in use (args in avc)
- * \param[out] aout not in use
- *
- * \retval EINVAL Error if some of the standard args aren't set
- * \retval EIO Error if the afs daemon hasn't started yet
- *
- * \post
- * Flush all cached contents of a volume. Exactly what stays and what
- * goes depends on the platform.
- *
- * \notes
- * Does not flush a file that a user has open and is using, because
- * it will be re-created on next write. Also purges the dnlc,
- * because things are screwed up.
- */
-DECL_PIOCTL(PFlushVolumeData)
+static int
+FlushVolumeData(struct VenusFid *afid, afs_ucred_t * acred)
{
afs_int32 i;
struct dcache *tdc;
struct vcache *tvc;
struct volume *tv;
- afs_int32 cell, volume;
+ afs_int32 all = 0;
+ afs_int32 cell = 0;
+ afs_int32 volume = 0;
struct afs_q *tq, *uq;
+ int code = 0;
#ifdef AFS_DARWIN80_ENV
vnode_t vp;
#endif
- AFS_STATCNT(PFlushVolumeData);
- if (!avc)
- return EINVAL;
- if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
- return EIO; /* Inappropriate ioctl for device */
-
- volume = avc->f.fid.Fid.Volume; /* who to zap */
- cell = avc->f.fid.Cell;
+ if (!afid) {
+ all = 1;
+ } else {
+ volume = afid->Fid.Volume; /* who to zap */
+ cell = afid->Cell;
+ }
/*
* Clear stat'd flag from all vnodes from this volume; this will
*/
loop:
ObtainReadLock(&afs_xvcache);
- i = VCHashV(&avc->f.fid);
- for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
+ for (i = (afid ? VCHashV(afid) : 0); i < VCSIZE; i = (afid ? VCSIZE : i+1)) {
+ for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
uq = QPrev(tq);
tvc = QTOVH(tq);
- if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
+ if (all || (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell)) {
if (tvc->f.states & CVInit) {
ReleaseReadLock(&afs_xvcache);
afs_osi_Sleep(&tvc->f.states);
continue;
}
#else
- AFS_FAST_HOLD(tvc);
+ if (osi_vnhold(tvc) != 0) {
+ continue;
+ }
#endif
ReleaseReadLock(&afs_xvcache);
-#ifdef AFS_BOZONLOCK_ENV
- afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
-#endif
ObtainWriteLock(&tvc->lock, 232);
-
- ObtainWriteLock(&afs_xcbhash, 458);
- afs_DequeueCallback(tvc);
- tvc->f.states &= ~(CStatd | CDirty);
- ReleaseWriteLock(&afs_xcbhash);
- if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
- osi_dnlc_purgedp(tvc);
- afs_TryToSmush(tvc, *acred, 1);
+ afs_ResetVCache(tvc, acred, 1);
ReleaseWriteLock(&tvc->lock);
-#ifdef AFS_BOZONLOCK_ENV
- afs_BozonUnlock(&tvc->pvnLock, tvc);
-#endif
#ifdef AFS_DARWIN80_ENV
vnode_put(AFSTOV(tvc));
#endif
AFS_FAST_RELE(tvc);
}
}
+ }
ReleaseReadLock(&afs_xvcache);
for (i = 0; i < afs_cacheFiles; i++) {
if (!(afs_indexFlags[i] & IFEverUsed))
continue; /* never had any data */
- tdc = afs_GetDSlot(i, NULL);
+ tdc = afs_GetValidDSlot(i);
+ if (!tdc) {
+ code = EIO;
+ break;
+ }
if (tdc->refCount <= 1) { /* too high, in use by running sys call */
ReleaseReadLock(&tdc->tlock);
- if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
- if (!(afs_indexFlags[i] & IFDataMod)) {
+ if (all || (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell)) {
+ if (!(afs_indexFlags[i] & (IFDataMod | IFFree | IFDiscarded))) {
/* if the file is modified, but has a ref cnt of only 1,
* then someone probably has the file open and is writing
* into it. Better to skip flushing such a file, it will be
* brought back immediately on the next write anyway.
*
+ * Skip if already freed.
+ *
* If we *must* flush, then this code has to be rearranged
* to call afs_storeAllSegments() first */
afs_FlushDCache(tdc);
ReleaseWriteLock(&afs_xdcache);
ObtainReadLock(&afs_xvolume);
- for (i = 0; i < NVOLS; i++) {
+ for (i = all ? 0 : VHash(volume); i < NVOLS; i++) {
for (tv = afs_volumes[i]; tv; tv = tv->next) {
- if (tv->volume == volume) {
+ if (all || tv->volume == volume) {
afs_ResetVolumeInfo(tv);
- break;
+ if (!all)
+ goto last;
}
}
}
+ last:
ReleaseReadLock(&afs_xvolume);
/* probably, a user is doing this, probably, because things are screwed up.
* maybe it's the dnlc's fault? */
osi_dnlc_purge();
- return 0;
+ return code;
}
+/*!
+ * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain not in use (args in avc)
+ * \param[out] aout not in use
+ *
+ * \retval EINVAL Error if some of the standard args aren't set
+ * \retval EIO Error if the afs daemon hasn't started yet
+ *
+ * \post
+ * Flush all cached contents of a volume. Exactly what stays and what
+ * goes depends on the platform.
+ *
+ * \notes
+ * Does not flush a file that a user has open and is using, because
+ * it will be re-created on next write. Also purges the dnlc,
+ * because things are screwed up.
+ */
+DECL_PIOCTL(PFlushVolumeData)
+{
+ AFS_STATCNT(PFlushVolumeData);
+ if (!avc)
+ return EINVAL;
+ if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
+ return EIO; /* Inappropriate ioctl for device */
+
+ return FlushVolumeData(&avc->f.fid, *acred);
+}
+
+/*!
+ * VIOC_FLUSHALL (14) - Flush whole volume's data for all volumes
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain not in use
+ * \param[out] aout not in use
+ *
+ * \retval EINVAL Error if some of the standard args aren't set
+ * \retval EIO Error if the afs daemon hasn't started yet
+ *
+ * \post
+ * Flush all cached contents. Exactly what stays and what
+ * goes depends on the platform.
+ *
+ * \notes
+ * Does not flush a file that a user has open and is using, because
+ * it will be re-created on next write. Also purges the dnlc,
+ * because things are screwed up.
+ */
+DECL_PIOCTL(PFlushAllVolumeData)
+{
+ AFS_STATCNT(PFlushAllVolumeData);
+
+ if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
+ return EIO; /* Inappropriate ioctl for device */
+
+ return FlushVolumeData(NULL, *acred);
+}
/*!
* VIOCGETVCXSTATUS (41) - gets vnode x status
return EINVAL;
num = count;
}
- if (afs_cr_gid(*acred) == RMTUSER_REQ ||
- afs_cr_gid(*acred) == RMTUSER_REQ_PRIV) { /* Handles all exporters */
+ if (afs_rmtsys_enable && (afs_cr_gid(*acred) == RMTUSER_REQ ||
+ afs_cr_gid(*acred) == RMTUSER_REQ_PRIV)) { /* Handles all exporters */
if (allpags && afs_cr_gid(*acred) != RMTUSER_REQ_PRIV) {
return EPERM;
}
#ifdef AFS_AIX51_ENV
newcred->cr_groupset.gs_union.un_groups[0] = g0;
newcred->cr_groupset.gs_union.un_groups[1] = g1;
-#elif defined(AFS_LINUX26_ENV)
-# ifdef AFS_LINUX26_ONEGROUP_ENV
+#elif defined(AFS_LINUX_ENV)
+# ifdef AFS_PAG_ONEGROUP_ENV
afs_set_cr_group_info(newcred, groups_alloc(1)); /* nothing sets this */
l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
h = ((g0-0x3f00) >> 14);
GROUP_AT(afs_cr_group_info(newcred), 1) = g1;
# endif
#elif defined(AFS_SUN510_ENV)
+# ifdef AFS_PAG_ONEGROUP_ENV
+ gids[0] = afs_get_pag_from_groups(g0, g1);
+ crsetgroups(newcred, 1, gids);
+# else
gids[0] = g0;
gids[1] = g1;
crsetgroups(newcred, 2, gids);
+# endif /* !AFS_PAG_ONEGROUP_ENV */
#else
newcred->cr_groups[0] = g0;
newcred->cr_groups[1] = g1;
#endif
#ifdef AFS_AIX_ENV
newcred->cr_ngrps = 2;
-#elif !defined(AFS_LINUX26_ENV) && !defined(AFS_SUN510_ENV)
-# if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_FBSD80_ENV)
+#elif !defined(AFS_LINUX_ENV) && !defined(AFS_SUN510_ENV)
+# if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX_ENV) || defined(AFS_FBSD_ENV)
newcred->cr_ngroups = 2;
# else
for (i = 2; i < NGROUPS; i++)
if (ainSize < sizeof(struct setspref))
return EINVAL;
-#if 0 /* num_servers is unsigned */
- if (sin->num_servers < 0)
- return EINVAL;
-#endif
if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
return ENOMEM;
{
afs_int32 code;
struct vcache *tvc;
- struct dcache *tdc;
struct VenusFid tfid;
char *bufp;
char *mount;
struct sysname_info sysState;
- afs_size_t offset, len;
AFS_STATCNT(PFlushMount);
+ memset(&sysState, 0, sizeof(sysState));
+
if (!avc)
return EINVAL;
if (afs_pd_getStringPtr(ain, &mount) != 0)
return EINVAL;
- code = afs_VerifyVCache(avc, areq);
- if (code)
- return code;
- if (vType(avc) != VDIR) {
- return ENOTDIR;
- }
- tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
- if (!tdc)
- return ENOENT;
- Check_AtSys(avc, mount, &sysState, areq);
- ObtainReadLock(&tdc->lock);
- do {
- code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
- } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
- ReleaseReadLock(&tdc->lock);
- afs_PutDCache(tdc); /* we're done with the data */
- bufp = sysState.name;
+ code = afs_LookupName(avc, areq, mount, &sysState, &tfid);
if (code) {
goto out;
}
+
+ bufp = sysState.name;
tfid.Cell = avc->f.fid.Cell;
tfid.Fid.Volume = avc->f.fid.Fid.Volume;
if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
- tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
+ tvc = afs_LookupVCache(&tfid, areq, avc, bufp);
} else {
- tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+ tvc = afs_GetVCache(&tfid, areq);
}
if (!tvc) {
- code = ENOENT;
+ code = EIO;
goto out;
}
- if (tvc->mvstat != 1) {
+ if (tvc->mvstat != AFS_MVSTAT_MTPT) {
afs_PutVCache(tvc);
code = EINVAL;
goto out;
}
-#ifdef AFS_BOZONLOCK_ENV
- afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
-#endif
ObtainWriteLock(&tvc->lock, 649);
- ObtainWriteLock(&afs_xcbhash, 650);
- afs_DequeueCallback(tvc);
- tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
- ReleaseWriteLock(&afs_xcbhash);
+ /* next reference will re-stat cache entry */
+ afs_StaleVCacheFlags(tvc, 0, CDirty);
/* now find the disk cache entries */
afs_TryToSmush(tvc, *acred, 1);
- osi_dnlc_purgedp(tvc);
if (tvc->linkData && !(tvc->f.states & CCore)) {
afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
tvc->linkData = NULL;
}
ReleaseWriteLock(&tvc->lock);
-#ifdef AFS_BOZONLOCK_ENV
- afs_BozonUnlock(&tvc->pvnLock, tvc);
-#endif
afs_PutVCache(tvc);
out:
if (sysState.allocked)
- osi_FreeLargeSpace(bufp);
+ osi_FreeLargeSpace(sysState.name);
return code;
}
tfid.Fid.Vnode = Fid->Vnode;
tfid.Fid.Unique = Fid->Unique;
- tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+ tvc = afs_GetVCache(&tfid, areq);
if (!tvc) {
afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
tfid.Fid.Vnode = Fid->Vnode;
tfid.Fid.Unique = Fid->Unique;
- tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
+ tvc = afs_GetVCache(&tfid, areq);
afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
if (!tvc)
if (tc) {
RX_AFS_GUNLOCK();
code =
- RXAFS_FsCmd(rxconn, Fid, Inputs,
- (struct FsCmdOutputs *)aout);
+ RXAFS_FsCmd(rxconn, Fid, Inputs, Outputs);
RX_AFS_GLOCK();
} else
code = -1;
return 0;
}
-#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
+#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX_ENV)
DECL_PIOCTL(PSetCachingThreshold)
{
cache_bypass_threshold = threshold;
afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
/* TODO: move to separate pioctl, or enhance pioctl */
- cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
+ if (threshold == AFS_CACHE_BYPASS_DISABLED)
+ cache_bypass_strategy = NEVER_BYPASS_CACHE;
+ else if (!threshold)
+ cache_bypass_strategy = ALWAYS_BYPASS_CACHE;
+ else
+ cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
}
/* Return the current size threshold */
DECL_PIOCTL(PCallBackAddr)
{
#ifndef UKERNEL
- afs_uint32 addr, code;
+ afs_uint32 code;
int srvAddrCount;
struct server *ts;
struct srvAddr *sa;
struct afs_conn *tc;
- afs_int32 i, j;
+ afs_int32 i, j, addr;
struct unixuser *tu;
struct srvAddr **addrs;
struct rx_connection *rxconn;
if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
return EIO; /* Inappropriate ioctl for device */
- if (!afs_osi_suser(acred))
+ if (!afs_osi_suser(*acred))
return EACCES;
if (afs_pd_getInt(ain, &addr) != 0)
if (!ts->cell) /* not really an active server, anyway, it must */
continue; /* have just been added by setsprefs */
+ if ((sa->sa_flags & SRVADDR_ISDOWN) == 0 && !afs_HaveCallBacksFrom(ts)) {
+ /* Server is up, and we have no active callbacks from it. */
+ continue;
+ }
+
/* get a connection, even if host is down; bumps conn ref count */
tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
- 1 /*force */ , 1 /*create */ , SHARED_LOCK, &rxconn);
+ 1 /*force */ , 1 /*create */ , SHARED_LOCK, 0, &rxconn);
afs_PutUser(tu, SHARED_LOCK);
if (!tc)
continue;
- if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
- if (sa->sa_flags & SRVADDR_ISDOWN) {
- rx_SetConnDeadTime(rxconn, 3);
- }
+ if (sa->sa_flags & SRVADDR_ISDOWN) {
+ rx_SetConnDeadTime(rxconn, 3);
+ }
#ifdef RX_ENABLE_LOCKS
- AFS_GUNLOCK();
+ AFS_GUNLOCK();
#endif /* RX_ENABLE_LOCKS */
- code = RXAFS_CallBackRxConnAddr(rxconn, &addr);
+ code = RXAFS_CallBackRxConnAddr(rxconn, &addr);
#ifdef RX_ENABLE_LOCKS
- AFS_GLOCK();
+ AFS_GLOCK();
#endif /* RX_ENABLE_LOCKS */
- }
+
afs_PutConn(tc, rxconn, SHARED_LOCK); /* done with it now */
} /* Outer loop over addrs */
+ afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
#endif /* UKERNEL */
return 0;
}
int i, cellNum, primaryFlag;
XDR xdrs;
struct unixuser *tu;
- struct vrequest treq;
+ struct vrequest *treq = NULL;
struct ktc_setTokenData tokenSet;
struct ktc_tokenUnion decodedToken;
if (tokenSet.flags & AFSTOKEN_EX_SETPAG) {
if (_settok_setParentPag(acred) == 0) {
- afs_InitReq(&treq, *acred);
- areq = &treq;
+ code = afs_CreateReq(&treq, *acred);
+ if (code) {
+ xdr_free((xdrproc_t) xdr_ktc_setTokenData, &tokenSet);
+ return code;
+ }
+ areq = treq;
}
}
out:
afs_ResetUserConns(tu);
afs_PutUser(tu, WRITE_LOCK);
+ afs_DestroyReq(treq);
return code;
}
+/*!
+ * VIOC_GETTOK2 (7) - Return a user's nth token, or token for a cell by
+ * name.
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain EITHER a string cellname
+ * OR an integer 'iterator' to specify the nth
+ * token.
+ *
+ * \param[out] aout XDR-encoded tokens from the user's tokenJar
+ *
+ * \retval EINVAL invalid input (bad integer, or invalid string)
+ * unable to extract token(s)
+ * \retval ENOMEM insufficient memory (returned from called routines)
+ * \retval EDOM (integer) request was out of bounds or the user has no tokens
+ * \retval ENOTCONN user found but has no valid token(s)
+ * \retval E2BIG token(s) do not fit in the output buffer
+ *
+ */
DECL_PIOCTL(PGetTokens2)
{
struct cell *cell = NULL;
char *cellName = NULL;
afs_int32 cellNum;
int code = 0;
+ int integer_in = 1; /* assume integer input */
time_t now;
XDR xdrs;
struct ktc_setTokenData tokenSet;
memset(&tokenSet, 0, sizeof(tokenSet));
/* No input data - return tokens for primary cell */
- /* 4 octets of data is an iterator count */
+ /* 4 octets of data is PROBABLY an iterator count */
/* Otherwise, treat as string & return tokens for that cell name */
if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
- /* Integer iterator - return tokens for the n'th cell found for user */
+ char *scratch = afs_pd_where(ain);
+
+ if (scratch[3] == '\0' && strlen(scratch) == 3)
+ integer_in = 0;
+ } else {
+ integer_in = 0;
+ }
+
+ if (integer_in) {
+ /* The misleadingly-named getNthCell actually return the nth valid
+ * token found for the specified user; there can never be a gap
+ * in the ordinals at this level.
+ */
if (afs_pd_getInt(ain, &iterator) != 0)
return EINVAL;
tu = getNthCell(areq->uid, iterator);
return EACCES;
}
afs_PutUser(tu, SHARED_LOCK);
- } else if (!afs_osi_suser(acred)) {
+ } else if (!afs_osi_suser(*acred)) {
return EACCES;
}