#include <afsconfig.h>
#include "afs/param.h"
-RCSID
- ("$Header$");
#include "afs/sysincludes.h" /* Standard vendor system headers */
#include "afsincludes.h" /* Afs-based standard headers */
#include "afs/afs_cbqueue.h"
#include "afs/nfsclient.h"
#include "afs/afs_osidnlc.h"
+#include "afs/unified_afs.h"
/* question: does afs_create need to set CDirty in the adp or the avc?
* I think we can get away without it, but I'm not sure. Note that
* afs_setattr is called in here for truncation.
*/
-#ifdef AFS_OSF_ENV
-int
-afs_create(struct nameidata *ndp, struct vattr *attrs)
-#else /* AFS_OSF_ENV */
#ifdef AFS_SGI64_ENV
int
afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, int flags,
- int amode, struct vcache **avcp, struct AFS_UCRED *acred)
+ int amode, struct vcache **avcp, afs_ucred_t *acred)
#else /* AFS_SGI64_ENV */
int
afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
enum vcexcl aexcl, int amode, struct vcache **avcp,
- struct AFS_UCRED *acred)
+ afs_ucred_t *acred)
#endif /* AFS_SGI64_ENV */
-#endif /* AFS_OSF_ENV */
{
-#ifdef AFS_OSF_ENV
- register struct vcache *adp = VTOAFS(ndp->ni_dvp);
- char *aname = ndp->ni_dent.d_name;
- enum vcexcl aexcl = NONEXCL; /* XXX - create called properly */
- int amode = 0; /* XXX - checked in higher level */
- struct vcache **avcp = (struct vcache **)&(ndp->ni_vp);
- struct ucred *acred = ndp->ni_cred;
-#endif
-
afs_int32 origCBs, origZaps, finalZaps;
- struct vrequest treq;
- register afs_int32 code;
- register struct conn *tc;
+ struct vrequest *treq = NULL;
+ afs_int32 code;
+ struct afs_conn *tc;
struct VenusFid newFid;
struct AFSStoreStatus InStatus;
- struct AFSFetchStatus OutFidStatus, OutDirStatus;
+ struct AFSFetchStatus *OutFidStatus, *OutDirStatus;
struct AFSVolSync tsync;
struct AFSCallBack CallBack;
afs_int32 now;
struct vcache *tvc;
struct volume *volp = 0;
struct afs_fakestat_state fakestate;
- XSTATS_DECLS OSI_VC_CONVERT(adp)
+ struct rx_connection *rxconn;
+ XSTATS_DECLS;
+ OSI_VC_CONVERT(adp);
+ AFS_STATCNT(afs_create);
- AFS_STATCNT(afs_create);
- if ((code = afs_InitReq(&treq, acred)))
+ OutFidStatus = osi_AllocSmallSpace(sizeof(struct AFSFetchStatus));
+ OutDirStatus = osi_AllocSmallSpace(sizeof(struct AFSFetchStatus));
+ memset(&InStatus, 0, sizeof(InStatus));
+
+ if ((code = afs_CreateReq(&treq, acred)))
goto done2;
afs_Trace3(afs_iclSetp, CM_TRACE_CREATE, ICL_TYPE_POINTER, adp,
if (strlen(aname) > AFSNAMEMAX) {
code = ENAMETOOLONG;
- goto done;
+ goto done3;
}
if (!afs_ENameOK(aname)) {
code = EINVAL;
- goto done;
+ goto done3;
}
switch (attrs->va_type) {
case VBLK:
case VFIFO:
/* We don't support special devices or FIFOs */
code = EINVAL;
- goto done;
+ goto done3;
default:
;
}
- code = afs_EvalFakeStat(&adp, &fakestate, &treq);
+ AFS_DISCON_LOCK();
+
+ code = afs_EvalFakeStat(&adp, &fakestate, treq);
if (code)
goto done;
tagain:
- code = afs_VerifyVCache(adp, &treq);
+ code = afs_VerifyVCache(adp, treq);
if (code)
goto done;
/** If the volume is read-only, return error without making an RPC to the
* fileserver
*/
- if (adp->states & CRO) {
+ if (adp->f.states & CRO) {
code = EROFS;
goto done;
}
- tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
+ if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
+ code = ENETDOWN;
+ goto done;
+ }
+
+ tdc = afs_GetDCache(adp, (afs_size_t) 0, treq, &offset, &len, 1);
ObtainWriteLock(&adp->lock, 135);
if (tdc)
ObtainSharedLock(&tdc->lock, 630);
* Make sure that the data in the cache is current. We may have
* received a callback while we were waiting for the write lock.
*/
- if (!(adp->states & CStatd)
- || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
+ if (!(adp->f.states & CStatd)
+ || (tdc && !hsame(adp->f.m.DataVersion, tdc->f.versionNo))) {
ReleaseWriteLock(&adp->lock);
if (tdc) {
ReleaseSharedLock(&tdc->lock);
if (tdc) {
/* see if file already exists. If it does, we only set
* the size attributes (to handle O_TRUNC) */
- code = afs_dir_Lookup(&tdc->f.inode, aname, &newFid.Fid); /* use dnlc first xxx */
+ code = afs_dir_Lookup(tdc, aname, &newFid.Fid); /* use dnlc first xxx */
if (code == 0) {
ReleaseSharedLock(&tdc->lock);
afs_PutDCache(tdc);
goto done;
}
/* found the file, so use it */
- newFid.Cell = adp->fid.Cell;
- newFid.Fid.Volume = adp->fid.Fid.Volume;
+ newFid.Cell = adp->f.fid.Cell;
+ newFid.Fid.Volume = adp->f.fid.Fid.Volume;
tvc = NULL;
if (newFid.Fid.Unique == 0) {
- tvc = afs_LookupVCache(&newFid, &treq, NULL, adp, aname);
+ tvc = afs_LookupVCache(&newFid, treq, NULL, adp, aname);
}
if (!tvc) /* lookup failed or wasn't called */
- tvc = afs_GetVCache(&newFid, &treq, NULL, NULL);
+ tvc = afs_GetVCache(&newFid, treq, NULL, NULL);
if (tvc) {
/* if the thing exists, we need the right access to open it.
* has mode -w-w-w, which is wrong.
*/
if ((amode & VREAD)
- && !afs_AccessOK(tvc, PRSFS_READ, &treq, CHECK_MODE_BITS)) {
+ && !afs_AccessOK(tvc, PRSFS_READ, treq, CHECK_MODE_BITS)) {
afs_PutVCache(tvc);
code = EACCES;
goto done;
}
-#if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
+#if defined(AFS_DARWIN80_ENV)
+ if ((amode & VWRITE) || VATTR_IS_ACTIVE(attrs, va_data_size))
+#elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
if ((amode & VWRITE) || (attrs->va_mask & AT_SIZE))
#else
if ((amode & VWRITE) || len != 0xffffffff)
#endif
{
/* needed for write access check */
- tvc->parentVnode = adp->fid.Fid.Vnode;
- tvc->parentUnique = adp->fid.Fid.Unique;
+ tvc->f.parent.vnode = adp->f.fid.Fid.Vnode;
+ tvc->f.parent.unique = adp->f.fid.Fid.Unique;
/* need write mode for these guys */
if (!afs_AccessOK
- (tvc, PRSFS_WRITE, &treq, CHECK_MODE_BITS)) {
+ (tvc, PRSFS_WRITE, treq, CHECK_MODE_BITS)) {
afs_PutVCache(tvc);
code = EACCES;
goto done;
}
}
-#if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
+#if defined(AFS_DARWIN80_ENV)
+ if (VATTR_IS_ACTIVE(attrs, va_data_size))
+#elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
if (attrs->va_mask & AT_SIZE)
#else
if (len != 0xffffffff)
goto done;
}
/* do a truncate */
-#if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
+#if defined(AFS_DARWIN80_ENV)
+ VATTR_INIT(attrs);
+ VATTR_SET_SUPPORTED(attrs, va_data_size);
+ VATTR_SET_ACTIVE(attrs, va_data_size);
+#elif defined(UKERNEL)
+ attrs->va_mask = ATTR_SIZE;
+#elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
attrs->va_mask = AT_SIZE;
#else
VATTR_NULL(attrs);
#endif
attrs->va_size = len;
ObtainWriteLock(&tvc->lock, 136);
- tvc->states |= CCreating;
+ tvc->f.states |= CCreating;
ReleaseWriteLock(&tvc->lock);
#if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
#if defined(AFS_SGI64_ENV)
code = afs_setattr(tvc, attrs, acred);
#endif /* SUN5 || SGI */
ObtainWriteLock(&tvc->lock, 137);
- tvc->states &= ~CCreating;
+ tvc->f.states &= ~CCreating;
ReleaseWriteLock(&tvc->lock);
if (code) {
afs_PutVCache(tvc);
}
}
*avcp = tvc;
- } else
- code = ENOENT; /* shouldn't get here */
+
+ } else {
+ /* Directory entry already exists, but we cannot fetch the
+ * fid it points to. */
+ code = EIO;
+ }
/* make sure vrefCount bumped only if code == 0 */
goto done;
}
}
-
+
/* if we create the file, we don't do any access checks, since
* that's how O_CREAT is supposed to work */
- if (adp->states & CForeign) {
+ if (adp->f.states & CForeign) {
origCBs = afs_allCBs;
origZaps = afs_allZaps;
} else {
}
InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
InStatus.ClientModTime = osi_Time();
- InStatus.Group = (afs_int32) acred->cr_gid;
+ InStatus.Group = (afs_int32) afs_cr_gid(acred);
if (AFS_NFSXLATORREQ(acred)) {
/*
* XXX The following is mainly used to fix a bug in the HP-UX
attrs->va_mode = 0x1b6; /* XXX default mode: rw-rw-rw XXX */
}
}
- InStatus.UnixModeBits = attrs->va_mode & 0xffff; /* only care about protection bits */
- do {
- tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
- if (tc) {
- hostp = tc->srvr->server; /* remember for callback processing */
- now = osi_Time();
- XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
- RX_AFS_GUNLOCK();
- code =
- RXAFS_CreateFile(tc->id, (struct AFSFid *)&adp->fid.Fid,
+
+ if (!AFS_IS_DISCONNECTED) {
+ /* If not disconnected, connect to the server.*/
+
+ InStatus.UnixModeBits = attrs->va_mode & 0xffff; /* only care about protection bits */
+ do {
+ tc = afs_Conn(&adp->f.fid, treq, SHARED_LOCK, &rxconn);
+ if (tc) {
+ hostp = tc->parent->srvr->server; /* remember for callback processing */
+ now = osi_Time();
+ XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
+ RX_AFS_GUNLOCK();
+ code =
+ RXAFS_CreateFile(rxconn, (struct AFSFid *)&adp->f.fid.Fid,
aname, &InStatus, (struct AFSFid *)
- &newFid.Fid, &OutFidStatus, &OutDirStatus,
+ &newFid.Fid, OutFidStatus, OutDirStatus,
&CallBack, &tsync);
- RX_AFS_GLOCK();
- XSTATS_END_TIME;
- CallBack.ExpirationTime += now;
- } else
- code = -1;
- } while (afs_Analyze
- (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_CREATEFILE,
- SHARED_LOCK, NULL));
-
-#if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
- if (code == EEXIST && aexcl == NONEXCL) {
- /* This lookup was handled in the common vn_open code in the
- * vnode layer */
- if (tdc) {
- ReleaseSharedLock(&tdc->lock);
- afs_PutDCache(tdc);
- }
- ReleaseWriteLock(&adp->lock);
- goto done;
- }
-#else /* AFS_OSF_ENV */
+ RX_AFS_GLOCK();
+ XSTATS_END_TIME;
+ CallBack.ExpirationTime += now;
+ } else
+ code = -1;
+ } while (afs_Analyze
+ (tc, rxconn, code, &adp->f.fid, treq, AFS_STATS_FS_RPCIDX_CREATEFILE,
+ SHARED_LOCK, NULL));
+
+ if ((code == EEXIST || code == UAEEXIST) &&
#ifdef AFS_SGI64_ENV
- if (code == EEXIST && !(flags & VEXCL)) {
+ !(flags & VEXCL)
#else /* AFS_SGI64_ENV */
- if (code == EEXIST && aexcl == NONEXCL) {
-#endif /* AFS_SGI64_ENV */
- /* if we get an EEXIST in nonexcl mode, just do a lookup */
- if (tdc) {
- ReleaseSharedLock(&tdc->lock);
- afs_PutDCache(tdc);
- }
- ReleaseWriteLock(&adp->lock);
-#if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
+ aexcl == NONEXCL
+#endif
+ ) {
+ /* if we get an EEXIST in nonexcl mode, just do a lookup */
+ if (tdc) {
+ ReleaseSharedLock(&tdc->lock);
+ afs_PutDCache(tdc);
+ }
+ ReleaseWriteLock(&adp->lock);
+
+
#if defined(AFS_SGI64_ENV)
- code =
- afs_lookup(VNODE_TO_FIRST_BHV((vnode_t *) adp), aname, avcp, NULL,
- 0, NULL, acred);
-#else
- code = afs_lookup(adp, aname, avcp, NULL, 0, NULL, acred);
-#endif /* AFS_SGI64_ENV */
-#else /* SUN5 || SGI */
- code = afs_lookup(adp, aname, avcp, acred);
-#endif /* SUN5 || SGI */
+ code = afs_lookup(VNODE_TO_FIRST_BHV((vnode_t *) adp), aname, avcp,
+ NULL, 0, NULL, acred);
+#elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
+ code = afs_lookup(adp, aname, avcp, NULL, 0, NULL, acred);
+#elif defined(UKERNEL)
+ code = afs_lookup(adp, aname, avcp, acred, 0);
+#elif !defined(AFS_DARWIN_ENV)
+ code = afs_lookup(adp, aname, avcp, acred);
+#endif
goto done;
- }
-#endif /* AFS_OSF_ENV */
- if (code) {
- if (code < 0) {
- ObtainWriteLock(&afs_xcbhash, 488);
- afs_DequeueCallback(adp);
- adp->states &= ~CStatd;
- ReleaseWriteLock(&afs_xcbhash);
- osi_dnlc_purgedp(adp);
- }
- ReleaseWriteLock(&adp->lock);
- if (tdc) {
- ReleaseSharedLock(&tdc->lock);
- afs_PutDCache(tdc);
- }
+ }
+
+ if (code) {
+ if (code < 0) {
+ afs_StaleVCache(adp);
+ }
+ ReleaseWriteLock(&adp->lock);
+ if (tdc) {
+ ReleaseSharedLock(&tdc->lock);
+ afs_PutDCache(tdc);
+ }
goto done;
- }
+ }
+
+ } else {
+ /* Generate a fake FID for disconnected mode. */
+ newFid.Cell = adp->f.fid.Cell;
+ newFid.Fid.Volume = adp->f.fid.Fid.Volume;
+ afs_GenFakeFid(&newFid, VREG, 1);
+ } /* if (!AFS_IS_DISCON_RW) */
+
/* otherwise, we should see if we can make the change to the dir locally */
if (tdc)
UpgradeSToWLock(&tdc->lock, 631);
- if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
+ if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, OutDirStatus, 1)) {
/* we can do it locally */
- code = afs_dir_Create(&tdc->f.inode, aname, &newFid.Fid);
+ ObtainWriteLock(&afs_xdcache, 291);
+ code = afs_dir_Create(tdc, aname, &newFid.Fid);
+ ReleaseWriteLock(&afs_xdcache);
if (code) {
ZapDCE(tdc);
- DZap(&tdc->f.inode);
+ DZap(tdc);
}
}
if (tdc) {
ReleaseWriteLock(&tdc->lock);
afs_PutDCache(tdc);
}
- newFid.Cell = adp->fid.Cell;
- newFid.Fid.Volume = adp->fid.Fid.Volume;
+ if (AFS_IS_DISCON_RW)
+ adp->f.m.LinkCount++;
+
+ newFid.Cell = adp->f.fid.Cell;
+ newFid.Fid.Volume = adp->f.fid.Fid.Volume;
ReleaseWriteLock(&adp->lock);
volp = afs_FindVolume(&newFid, READ_LOCK);
* would fail, since no call would be able to update the local vnode status after modifying
* a file on a file server. */
ObtainWriteLock(&afs_xvcache, 138);
- if (adp->states & CForeign)
+ if (adp->f.states & CForeign)
finalZaps = afs_allZaps; /* do this before calling newvcache */
else
finalZaps = afs_evenZaps; /* do this before calling newvcache */
ObtainWriteLock(&afs_xcbhash, 489);
finalCBs = afs_evenCBs;
/* add the callback in */
- if (adp->states & CForeign) {
- tvc->states |= CForeign;
+ if (adp->f.states & CForeign) {
+ tvc->f.states |= CForeign;
finalCBs = afs_allCBs;
}
if (origCBs == finalCBs && origZaps == finalZaps) {
- tvc->states |= CStatd; /* we've fake entire thing, so don't stat */
- tvc->states &= ~CBulkFetching;
- tvc->cbExpires = CallBack.ExpirationTime;
- afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), volp);
+ tvc->f.states |= CStatd; /* we've fake entire thing, so don't stat */
+ tvc->f.states &= ~CBulkFetching;
+ if (!AFS_IS_DISCON_RW) {
+ tvc->cbExpires = CallBack.ExpirationTime;
+ afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), volp);
+ }
} else {
- afs_DequeueCallback(tvc);
- tvc->states &= ~(CStatd | CUnique);
- tvc->callback = 0;
- if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
- osi_dnlc_purgedp(tvc);
+ afs_StaleVCacheFlags(tvc,
+ AFS_STALEVC_CBLOCKED | AFS_STALEVC_CLEARCB,
+ CUnique);
}
ReleaseWriteLock(&afs_xcbhash);
- afs_ProcessFS(tvc, &OutFidStatus, &treq);
+ if (AFS_IS_DISCON_RW) {
+ afs_DisconAddDirty(tvc, VDisconCreate, 0);
+ afs_GenDisconStatus(adp, tvc, &newFid, attrs, treq, VREG);
+ } else {
+ afs_ProcessFS(tvc, OutFidStatus, treq);
+ }
+
+ tvc->f.parent.vnode = adp->f.fid.Fid.Vnode;
+ tvc->f.parent.unique = adp->f.fid.Fid.Unique;
ReleaseWriteLock(&tvc->lock);
*avcp = tvc;
code = 0;
- } else
- code = ENOENT;
+
+ } else {
+ /* Cannot create a new vcache. */
+ code = EIO;
+ }
} else {
/* otherwise cache entry already exists, someone else must
* have created it. Comments used to say: "don't need write
ReleaseWriteLock(&afs_xvcache);
done:
+ AFS_DISCON_UNLOCK();
+
+ done3:
if (volp)
afs_PutVolume(volp, READ_LOCK);
if (code == 0) {
- afs_AddMarinerName(aname, *avcp);
+ if (afs_mariner)
+ afs_AddMarinerName(aname, *avcp);
/* return the new status in vattr */
afs_CopyOutAttrs(*avcp, attrs);
+ if (afs_mariner)
+ afs_MarinerLog("store$Creating", *avcp);
}
-#ifdef AFS_OSF_ENV
- if (!code && !strcmp(aname, "core"))
- tvc->states |= CCore1;
-#endif
afs_PutFakeStat(&fakestate);
- code = afs_CheckCode(code, &treq, 20);
+ code = afs_CheckCode(code, treq, 20);
+ afs_DestroyReq(treq);
done2:
-#ifdef AFS_OSF_ENV
- afs_PutVCache(adp);
-#endif /* AFS_OSF_ENV */
-
+ osi_FreeSmallSpace(OutFidStatus);
+ osi_FreeSmallSpace(OutDirStatus);
return code;
}
* and dcache entry write-locked.
*/
int
-afs_LocalHero(register struct vcache *avc, register struct dcache *adc,
- register AFSFetchStatus * astat, register int aincr)
+afs_LocalHero(struct vcache *avc, struct dcache *adc,
+ AFSFetchStatus * astat, int aincr)
{
- register afs_int32 ok;
+ afs_int32 ok;
afs_hyper_t avers;
AFS_STATCNT(afs_LocalHero);
hset64(avers, astat->dataVersionHigh, astat->DataVersion);
- /* this *is* the version number, no matter what */
+ /* avers *is* the version number now, no matter what */
+
if (adc) {
- ok = (hsame(avc->m.DataVersion, adc->f.versionNo) && avc->callback
- && (avc->states & CStatd) && avc->cbExpires >= osi_Time());
+ /* does what's in the dcache *now* match what's in the vcache *now*,
+ * and do we have a valid callback? if not, our local copy is not "ok" */
+ ok = (hsame(avc->f.m.DataVersion, adc->f.versionNo) && avc->callback
+ && (avc->f.states & CStatd) && avc->cbExpires >= osi_Time());
} else {
ok = 0;
}
+ if (ok) {
+ /* check that the DV on the server is what we expect it to be */
+ afs_hyper_t newDV;
+ hset(newDV, adc->f.versionNo);
+ hadd32(newDV, aincr);
+ if (!hsame(avers, newDV)) {
+ ok = 0;
+ }
+ }
#if defined(AFS_SGI_ENV)
osi_Assert(avc->v.v_type == VDIR);
#endif
/* The bulk status code used the length as a sequence number. */
/* Don't update the vcache entry unless the stats are current. */
- if (avc->states & CStatd) {
- hset(avc->m.DataVersion, avers);
+ if (avc->f.states & CStatd) {
+ afs_SetDataVersion(avc, &avers);
#ifdef AFS_64BIT_CLIENT
- FillInt64(avc->m.Length, astat->Length_hi, astat->Length);
-#else /* AFS_64BIT_ENV */
- avc->m.Length = astat->Length;
-#endif /* AFS_64BIT_ENV */
- avc->m.Date = astat->ClientModTime;
+ FillInt64(avc->f.m.Length, astat->Length_hi, astat->Length);
+#else /* AFS_64BIT_CLIENT */
+ avc->f.m.Length = astat->Length;
+#endif /* AFS_64BIT_CLIENT */
+ avc->f.m.Date = astat->ClientModTime;
}
if (ok) {
/* we've been tracking things correctly */
} else {
if (adc) {
ZapDCE(adc);
- DZap(&adc->f.inode);
+ DZap(adc);
}
- if (avc->states & CStatd) {
+ if (avc->f.states & CStatd) {
osi_dnlc_purgedp(avc);
}
return 0;